Open-source project
guzzle/guzzle avatar
guzzle/guzzle

Guzzle 8.2: the PHP HTTP client that hides its transport

Guzzle, an extensible PHP HTTP client

23,453 stars2,390 forksPHPMIT

At a glance

What is it?
Guzzle is a PHP HTTP client built on PSR-7 messages and a middleware stack. It is the default choice for calling web services from PHP, but the abstraction has edges worth knowing before you adopt it.
Who is it for?
Adopt Guzzle when you need one client for sync and async HTTP calls across PHP 7.4 through 8.6, and when PSR-7 or PSR-18 interop matters to your stack. Do not adopt it if you are on PHP 8.7 or newer, since the version guidance in the README caps 8.2 at <8.7, or if you want a client that brings its own transport rather than abstracting one.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 25 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Guzzle solves for PHP services

PHP applications rarely talk to one API. They call a payment provider, a search index, an internal microservice, and a third-party identity endpoint, often in the same request cycle. Writing that with raw cURL means repeating header assembly, query-string encoding, redirect handling and error mapping for every call site. Guzzle exists to collapse that repetition into one client object.

The audience is PHP developers integrating with web services, and the README names that directly: Guzzle is "a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services." The same interface covers query strings, POST bodies, streaming uploads and downloads, cookies and JSON payloads. If your integration code is mostly one HTTP call after another, Guzzle is aimed at you.

The second audience is library authors. Because Guzzle uses PSR-7 interfaces for requests, responses and streams, and supports PSR-18, code written against those interfaces can be handed a different client without rewriting call sites. That interoperability is the part that matters most for packages that cannot dictate which HTTP client their users have.

How the client, handlers and middleware fit together

The architecture has three layers, and the README describes all three. At the top is the client, which builds a request and returns a response. Below it sits the handler, the component that performs the actual transfer. Guzzle "abstracts away the underlying HTTP transport, allowing you to write environment and transport agnostic code; i.e., no hard dependency on cURL, PHP streams, sockets, or non-blocking event loops."

That sentence is the design decision worth pausing on. The transport is not fixed. Which handler is selected depends on the environment, and the repository ships a handlers document rather than baking a choice into the client. The upside is portability: the same request code runs where cURL is available and where it is not. The downside is that performance and behaviour are properties of the handler, not of Guzzle itself, so two applications on the same Guzzle version can behave differently.

The third layer is middleware, which the README describes as a system that "allows you to augment and compose client behavior." Middleware wraps the handler stack, so logging, retry logic or header injection can be added without touching call sites. Sync and async requests share the same interface, which means a middleware written for one path generally applies to the other. The docs directory carries separate pages for handlers and middleware, so the project treats them as distinct concepts rather than one configuration surface.

Installing Guzzle with Composer and sending a first request

The README gives Composer as the recommended installation path. One command pulls the package and its dependencies into your project. Run it from the project root, and Composer will add the entry to composer.json and install the library under vendor/.

bash
composer require guzzlehttp/guzzle

With the package installed, the Quick Start example in the README is the shortest path to a working call. It creates a client with no arguments, issues a GET, and reads status, a header and the body from the response.

php
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://api.example.com/users/123');

echo $response->getStatusCode(); // 200
echo $response->getHeaderLine('content-type'); // 'application/json'
echo $response->getBody(); // '{"id": 123, "name": "Ada"}'

The three accessors are the ones you will use constantly. getStatusCode() returns the integer status. getHeaderLine() returns a single header value as a string, which is what you want for content-type. getBody() returns the response body, and the README's comment shows it being echoed directly. For anything beyond this, the README points to docs/quick-start.md and a set of topic pages covering request options, cookies, exceptions, handlers and middleware.

If you prefer to try Guzzle without touching your host PHP installation, the repository ships a Dockerfile. It builds a stage from composer:latest, runs composer init with the name guzzlehttp/test, and requires guzzlehttp/guzzle, then copies the result into a php:7.4 stage. That gives a container with Guzzle and its dependencies already present, which is useful for a throwaway script.

Where Guzzle stops being the right tool

The version guidance table is the first real constraint. Guzzle 8.2 supports PHP >=7.4,<8.7. Guzzle 7.15 is listed as Maintenance for PHP >=7.2.5,<8.7, and 6.5 is End of Life for PHP >=5.5,<8.0. If your runtime is PHP 8.7 or later, the README's table does not list a Guzzle version that supports it. That is a hard boundary, not a preference.

The transport abstraction has a second cost. Because there is no hard dependency on cURL, streams or sockets, the client can run in environments where none of the fast paths exist. The README does not state which handler is chosen under which conditions; it points to docs/handlers.md instead. If your workload is throughput-sensitive, that document is the one to read before you assume cURL is doing the work.

There is also a scope limit. Guzzle is an HTTP client, not a service SDK. It will not build signed AWS requests, paginate a vendor API, or retry with a provider-specific backoff for you. Those belong in middleware or in a package built on top of the client. If you want a client that already knows a specific API's conventions, Guzzle is the layer underneath it, not a replacement for it.

Guzzle against Symfony HttpClient

The closest alternative in the PHP ecosystem is Symfony HttpClient, and the difference is architectural rather than cosmetic. Symfony's component is built around a set of scoped clients and its own contract interfaces, and it is designed to sit inside the Symfony framework's configuration and dependency injection. Guzzle is framework-neutral and its contract is PSR-7 and PSR-18.

That distinction drives adoption decisions. If your application already uses PSR-7 messages throughout, Guzzle hands you the same message objects it accepts, and the README notes this is what "allows you to utilize other PSR-7 compatible libraries with Guzzle." If you want a client that other PSR-18 consumers can swap in and out, Guzzle's PSR-18 support is the relevant feature. Symfony HttpClient's integration story is stronger inside Symfony and weaker outside it.

Neither is universally better. Guzzle's middleware model composes behaviour around a handler stack, which suits teams that want to add logging or retry logic once and apply it everywhere. A framework-integrated client suits teams that want configuration to live in framework config files. The choice usually follows from whether your HTTP code is framework code or library code.

Maintenance, licensing and the upgrade path

Guzzle is MIT licensed, and the README states it plainly: "Guzzle is made available under the MIT License (MIT)." For most adopters that means permissive use with attribution, but the licence file is the authority and this article is not legal advice. Commercial support is offered through the Tidelift Subscription, which the README describes as covering Guzzle and other packages.

The repository is not archived, and the last push was on 2026-09-06. The 8.2.0 release carries the same date, with 8.1.0 and 8.0.3 both dated 2026-08-24. That is a recent cadence, and the version guidance table shows a deliberate policy: 8.2 is Latest, 7.15 is Maintenance, 6.5 is End of Life. If you are on 6.x, you are outside the supported set.

Upgrade cost is documented rather than implied. The repository root contains UPGRADING.md and CHANGELOG.md, and the README links both. For a major-version jump, UPGRADING.md is the file to read first, since the README itself does not enumerate breaking changes. The repository also carries a Makefile with targets for tests, coverage, static analysis via phpstan, and code style via php-cs-fixer, which tells you what a contribution or a local verification run is expected to pass.

Editorial conclusion

Adopt Guzzle when you need one client for sync and async HTTP calls across PHP 7.4 through 8.6, and when PSR-7 or PSR-18 interop matters to your stack. Do not adopt it if you are on PHP 8.7 or newer, since the version guidance in the README caps 8.2 at <8.7, or if you want a client that brings its own transport rather than abstracting one. Before committing, check which transport your runtime actually uses, because the README states Guzzle has no hard dependency on cURL, streams or sockets, and the behaviour you get depends on what is installed.

Frequently asked questions

How do I install Guzzle in PHP?

The README recommends Composer. Running composer require guzzlehttp/guzzle adds the package and its dependencies to your project.

How do I use Guzzle in PHP?

The README's Quick Start creates a client with new \GuzzleHttp\Client(), calls request('GET', $url), and reads the result through getStatusCode(), getHeaderLine() and getBody(). Longer examples live in docs/quick-start.md.

What is Guzzle?

Guzzle is a PHP HTTP client. The README describes it as making it easy to send HTTP requests and trivial to integrate with web services, with PSR-7 messages and a middleware system for composing client behaviour.

How do I install Guzzle?

The README gives Composer as the recommended way. The install command is composer require guzzlehttp/guzzle, run from your project root.

How do I use Guzzle?

Create a client with new \GuzzleHttp\Client() and call request() with an HTTP method and URL. The response exposes getStatusCode(), getHeaderLine() and getBody(). The README's Quick Start shows this sequence.

Official sources

  1. guzzle/guzzle on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/guzzle-guzzle.svg)](https://hysenlabs.com/projects/guzzle-guzzle)