# elasticsearch-php: 500 endpoints, one PSR-shaped client

> elasticsearch-php is the official PHP client for Elasticsearch, exposing more than 500 endpoints over PSR-7 messages and PSR-18 HTTP clients, with a built-in cURL transport replacing Guzzle since 9.0. It is versioned in lockstep with the Elasticsearch server and released quarterly, with v9.5.0 on 2026-08-04.

**elastic/elasticsearch-php** — Official PHP client for Elasticsearch.

- Repository: https://github.com/elastic/elasticsearch-php
- Website: https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html
- Stars: 5,336 · Forks: 963
- Language: PHP
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/elastic-elasticsearch-php

## An official client measured in endpoints

The one-sentence description is accurate and undersells the surface: this is the official PHP client for Elasticsearch, and it offers 500+ endpoints for interacting with a cluster, the full REST API surface of the server rendered as PHP methods. The README deliberately demonstrates only the basics, index, search and delete, through anchors into the getting-started documentation, covering creating an index, indexing, getting, searching, updating and deleting documents, and deleting the index. For running the server itself, the documented local path is a single shell line that starts both Elasticsearch and Kibana:

```bash
curl -fsSL https://elastic.co/start-local | sh
```

The alternative is a free Elastic Cloud trial, and both paths end at the same client. The audience is any PHP application, framework or plain script, that needs search, logging aggregation or analytics from an Elasticsearch deployment without hand-building HTTP requests per endpoint. The endpoint count is the appeal in practice: whatever capability the server grows, the corresponding method already exists here, named after the API and documented in PHPDoc, rather than arriving as a URL to construct and debug by hand.

## Versioned in lockstep with the server

The versioning rule is stricter than most libraries and worth internalizing before choosing a version. The client is versioned and released alongside the Elasticsearch server, and the guidance is explicit: use the most recent library version within the major version of your server. For Elasticsearch 8.16, that means 8.16 or above of the library, but not 9.0. A compatibility table maps main to main, 9.x to 9.x and 8.x to 8.x. Forward compatibility has a precise meaning here: clients communicate with greater or equal minor server versions without breaking, but an 8.12 client does not automatically gain the new features of an 8.13 server, the 8.13 client is required for that. Backwards compatibility with older servers is limited to default distributions and carries no guarantees. Release cadence is roughly quarterly, v9.3.0 on 2026-02-04, v9.4.0 on 2026-05-06 and v9.5.0 on 2026-08-04, with the last repository push on 2026-09-28, and the client supports currently maintained PHP versions. The lockstep model has a planning consequence worth stating: a server upgrade and a client upgrade are one project, and pinning the client while upgrading the server is precisely the combination the compatibility notes exist to prevent, while the quarterly rhythm gives teams a predictable point at which new server features become reachable from PHP.

## PSR-7 and PSR-18: the client is ordinary HTTP underneath

Version 9.0.0 kept the 8.x architecture, which rests on two PHP standards: PSR-7 for HTTP messages and PSR-18 for HTTP client communications. The practical consequence of that choice became visible in the same release, when the Guzzle dependency was removed entirely. By default the client now uses a built-in cURL-based PSR-18 implementation when no other PSR-18 compatible client is detected, through the companion elastic-transport-php library at its own 9.0.0, and any PSR-18 client an application already runs can be plugged in instead. For dependency-sensitive PHP projects this is the difference between adopting the official client and writing a thin REST wrapper: the client adds no HTTP framework of its own, respects the interfaces the ecosystem already standardized, and gets out of the way. The transport lives in a sibling repository, elastic-transport-php, released on its own line, so the HTTP layer evolves independently of the endpoint surface, and BREAKING_CHANGES.md records what moved across both when a major version lands. The product-response check is visible in the mocking example, where a valid response carries the Elasticsearch header check and product name.

## Serverless merged in, detected and guarded

The serverless story is a case study in consolidation done carefully. The separate elastic/elasticsearch-serverless client is deprecated, and its functionality was merged back into this one, with zero impact claimed on default behavior. Endpoints available in serverless carry a @group serverless attribute in their PHPDoc, and calling an endpoint that exists but is not available in serverless mode returns a 410 HTTP error with a message saying exactly that, so the failure is legible rather than mysterious. Detection is layered: the client recognizes serverless automatically when the URL is Elastic-managed, such as *.elastic.cloud, and when a proxy hides that, from the first response. Explicit control exists too, Client::setServerless(true), false by default, for topologies where neither signal suffices. One client binary, one API surface, two deployment models, with the boundary enforced at the endpoint level. The @group serverless marker doubles as documentation tooling: searching the source for the attribute yields the exact serverless-capable surface, which is faster than cross-referencing the server's own capability tables when planning a serverless deployment.

## To mock the client, mock PSR-18

Testing is where the PSR architecture pays its second dividend: the documented way to mock the Elasticsearch client is simply to mock a PSR-18 HTTP client, with no Elasticsearch-specific test doubles required. The README's example uses php-http/mock-client with a PSR-7 response from Nyholm:

```php
use Elastic\Elasticsearch\ClientBuilder;
use Elastic\Elasticsearch\Response\Elasticsearch;
use Http\Mock\Client;
use Nyholm\Psr7\Response;

$mock = new Client(); // This is the mock client

$client = ClientBuilder::create()
    ->setHttpClient($mock)
    ->build();
```

Responses are queued onto the mock, and endpoint calls return them:

```php
$response = new Response(
    200,
    [Elasticsearch::HEADER_CHECK => Elasticsearch::PRODUCT_NAME],
    'This is the body!'
);
$mock->addResponse($response);

$result = $client->info(); // Just calling an Elasticsearch endpoint

echo $result->asString(); // This is the body!
```

A test suite built this way needs no live cluster, no containers and no network, which is the property that makes endpoint-heavy clients testable at all. Because result objects wrap PSR-7 responses, assertions can inspect status codes, headers and bodies through the standard interfaces rather than client-specific accessors, keeping the test layer portable if the HTTP client ever changes.

## A test matrix readable from the file names

The repository's quality infrastructure is legible before you open a single config file. Beside the unit tests driven by phpunit.xml.dist sit phpunit-integration-tests.xml, phpunit-integration-cloud-tests.xml, phpunit-yaml-serverless-tests.xml and phpunit-yaml-stack-tests.xml, a four-way split between local integration, cloud, serverless and full-stack YAML-driven suites, matching exactly the deployment models the client supports. Static analysis runs under phpstan with a committed configuration, and CI lives in Buildkite alongside GitHub workflows. The YAML-driven suites imply that test scenarios are declared as data and executed against the client, an arrangement that lets the same definitions be shared across Elastic's official language clients rather than rewritten per language. The examples directory is thin but pointed, holding a dense_vector_benchmark.php, a benchmark for vector search, the workload class that motivates much of current Elasticsearch interest. Catalog metadata appears as catalog-info.yaml for Backstage-style service discovery, and AGENTS.md continues the pattern of repositories that onboard coding agents deliberately.

## A README that routes rather than teaches

The README's own structure is a deliberate choice worth naming: installation and connecting do not appear as inline copy-paste blocks but as links into the getting-started documentation on elastic.co, and the usage section is a table of contents into the server's REST API reference. The rationale is maintenance: a client that tracks 500 server endpoints cannot keep a README tutorial honest, so the README routes to the source of truth and reserves its own space for what is specific to this library, versioning rules, compatibility semantics, the 9.0 breaking changes and the mocking pattern. BREAKING_CHANGES.md and CHANGELOG.md carry the release history, the former being the document to read before any major bump, and the NOTICE file records attribution alongside the MIT license. For an integrator, the lesson is where to look: architecture and boundaries here, operations in the official docs, and the exact endpoint surface in the server reference.

## Conclusion

Use elasticsearch-php when a PHP application needs Elasticsearch's search and analytics, and you want endpoint coverage that tracks the server release for release. Talk to the REST API directly with any HTTP client if your surface is two endpoints and a dependency is not worth it. Verify first that your client major version matches your server, 9.x for 9.x and 8.x for 8.x per the compatibility table, that your PHP version is currently maintained, and read BREAKING_CHANGES.md before any major upgrade, since that file is where the contract actually lives.

## FAQ

### What is elasticsearch-php?

elasticsearch-php is the official PHP client for Elasticsearch, an MIT-licensed Composer package exposing more than 500 endpoints for interacting with a cluster, from indexing and searching documents to managing indices.

### How do you run Elasticsearch locally for PHP development?

Run curl -fsSL https://elastic.co/start-local | sh to start Elasticsearch and Kibana on your local machine, or sign up for a free Elastic Cloud trial. The PHP client then connects as described in the getting-started documentation.

### How do you mock the elasticsearch-php client in tests?

Mock a PSR-18 HTTP client and inject it with ClientBuilder::setHttpClient(), for example php-http/mock-client. Queue responses with addResponse(), and endpoint calls such as $client->info() return them, so no live cluster is needed.

## Sources

- [elastic/elasticsearch-php on GitHub](https://github.com/elastic/elasticsearch-php)
- [License: MIT](https://github.com/elastic/elasticsearch-php/blob/main/LICENSE)
- [Project website](https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html)
- [README](https://github.com/elastic/elasticsearch-php/blob/main/README.md)
- [Releases](https://github.com/elastic/elasticsearch-php/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/elastic-elasticsearch-php
