NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Packagist · #593 most downloaded on Packagist
PHP wrapper for the Meilisearch API
Last release today
07 Oct 2026
Release timing varies
gaps range from 8 days to 3 months
Rarely documented
notes for 4 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
80 releases · first in 2020
One column per quarter.
If you're migrating from v1.x , read the complete migration guide .
If you're migrating from v1.x, read the complete migration guide.
Index instead of IndexesThe per-index object from $client->index() / $client->getIndex() is now Meilisearch\Endpoints\Index. Metadata is lazy-loaded; fetchInfo() and fetchPrimaryKey() were removed.
Update type hints, imports, and code that fetched index metadata or assumed getIndex() made an HTTP call.
Rename Indexes to Index
// Before (v1.x)
use Meilisearch\Endpoints\Indexes;
function handle(Indexes $index): void { /* ... */ }
// After (v2.x)
use Meilisearch\Endpoints\Index;
function handle(Index $index): void { /* ... */ }getIndex() is now lazy
// Before (v1.x) - threw ApiException immediately if the index didn't exist
$index = $client->getIndex('missing');
// After (v2.x) - the call to a getter triggers the fetch (and any exception)
$index = $client->getIndex('missing');
$index->getPrimaryKey(); // ApiException thrown hereCall getters instead of fetchInfo() / fetchPrimaryKey()
// Before (v1.x)
$index = $client->index('books');
$index->fetchInfo();
$primaryKey = $index->fetchPrimaryKey();
// After (v2.x)
$index = $client->index('books');
$primaryKey = $index->getPrimaryKey(); // loads on demandgetUid(), getCreatedAt(), getUpdatedAt() are no longer nullable
// Before (v1.x)
$date = $index->getCreatedAt();
if ($date !== null) {
echo $date->format(DATE_ATOM);
}
// After (v2.x)
echo $index->getCreatedAt()->format(DATE_ATOM);multiSearch() now takes MultiSearchQuerysetIndexUid() and setFederationOptions() were moved off SearchQuery and onto the new MultiSearchQuery class. SearchQuery is now only for single-index search.
Update multi-search and federation query construction.
Use MultiSearchQuery for multiSearch()
// Before (v1.x)
use Meilisearch\Contracts\SearchQuery;
$client->multiSearch([
(new SearchQuery())->setIndexUid('books')->setQuery('prince'),
(new SearchQuery())->setIndexUid('songs')->setQuery('be'),
]);
// After (v2.x)
use Meilisearch\Contracts\MultiSearchQuery;
$client->multiSearch([
(new MultiSearchQuery())->setIndexUid('books')->setQuery('prince'),
(new MultiSearchQuery())->setIndexUid('songs')->setQuery('be'),
]);Use MultiSearchQuery for federation options
// Before (v1.x)
$query = (new SearchQuery())
->setIndexUid('books')
->setFederationOptions((new FederationOptions())->setWeight(0.5));
// After (v2.x)
$query = (new MultiSearchQuery())
->setIndexUid('books')
->setFederationOptions((new FederationOptions())->setWeight(0.5));IndexStats objectIndex stats APIs no longer return array-based responses. They now return a typed IndexStats object.
Update code that reads index stats fields to use getter methods.
$stats = $index->stats();
// Before (v1.x)
$count = $stats['numberOfDocuments'];
$indexing = $stats['isIndexing'];
$fields = $stats['fieldDistribution'];
// After (v2.x)
$count = $stats->getNumberOfDocuments();
$indexing = $stats->isIndexing();
$fields = $stats->getFieldDistribution();getSettings() returns plain arrays for nested settingssynonyms, typoTolerance, faceting, and embedders are now plain arrays instead of iterable setting objects, so iterator_to_array() is no longer needed.
Update code that converts nested settings to arrays.
$settings = $index->getSettings();
// Before (v1.x)
$typoTolerance = iterator_to_array($settings['typoTolerance']);
$synonyms = iterator_to_array($settings['synonyms']);
// After (v2.x)
$typoTolerance = $settings['typoTolerance'];
$synonyms = $settings['synonyms'];Batch objectsBatch APIs no longer return array-based responses. They now return typed Batch objects.
Update code that reads batch fields or lists batches.
// Before (v1.x)
$batch = $client->getBatch($uid);
$uid = $batch['uid'];
$startedAt = $batch['startedAt']; // string
$total = $batch['stats']['totalNbTasks'];
// After (v2.x)
$batch = $client->getBatch($uid);
$uid = $batch->getUid();
$startedAt = $batch->getStartedAt(); // \DateTimeImmutable
$total = $batch->getStats()->getTotalNbTasks();This also applies to $client->getBatches(). getResults() now returns an array of Batch objects.
// Before (v1.x)
$batches = $client->getBatches();
$uid = $batches->getResults()[0]['uid'];
// After (v2.x)
$batches = $client->getBatches();
$uid = $batches->getResults()[0]->getUid();progress is a BatchProgress object while the batch is running, and null when it has finished.
// Before (v1.x)
$percent = $batch['progress']['percentage'] ?? null;
// After (v2.x)
$percent = $batch->getProgress()?->getPercentage();Indexes stats, settings, and search (#931) @StriftBatch results (#928) @StriftIndexes stats, settings, and search (#931) @StriftindexSize and usedIndexSize to IndexStats (#946) @murilolivoratowait() tests with HTTP-stubbed polling (#947) @StriftThanks to @Strift, @murilolivorato and @norkunas! 🎉
See full changelog: v2.0.0-beta.7...v2.0.0-beta.8
Typehint HandlesSystem::health return type ( #927 ) @Strift
HandlesDocuments::getDocument. (#926) @StriftThanks to @Strift, @dependabot[bot], @mvanhorn, Matt Van Horn and dependabot[bot]! 🎉
See full changelog: v2.0.0-beta.6...v2.0.0-beta.7
If you're migrating from v1.x , read the complete migration guide .
If you're migrating from v1.x, read the complete migration guide.
API key methods no longer accept array-based write payloads or return plain list shapes. They now use CreateKeyQuery and UpdateKeyQuery for requests, KeysResults for lists, and KeyAction for actions.
// Before (v1.x)
$key = $client->createKey([
'description' => 'tenant token key',
'actions' => ['*'],
'indexes' => ['tenant*'],
'expiresAt' => '2055-10-02T00:00:00Z',
]);
// After (v2.x)
$key = $client->createKey(new CreateKeyQuery(
actions: [KeyAction::Any],
indexes: ['tenant*'],
description: 'tenant token key',
expiresAt: new DateTimeImmutable('2055-10-02T00:00:00Z'),
));The client updateKey method accepts an UpdateKeyQuery, which works similarly. It allows clearing the key name or description by passing null.
Additionally, KeysResults::count() was removed; use count($keysResults) instead.
SimilarDocumentsQuery, FacetSearchResult, and SearchResult are now finalThese other changes only pertain to PHPStan type hints improvements:
DocumentsResults (#908) @norkunasData's ArrayAccess methods (#912) @norkunasshowPerformanceDetails option (#871) @QDenkadistinct in federated search requests (#892) @mvanhornarray_key_exists instead of isset in Task::offsetExists (#870) @norkunasThanks to @QDenka, @Strift, @curquiza, @mvanhorn and @norkunas! 🎉
See full changelog: v2.0.0-beta.5...v2.0.0-beta.6
Note This replaces the incorrect v2.0.0-beta.4 release tagged from the wrong branch.
Note
This replaces the incorrect v2.0.0-beta.4 release tagged from the wrong branch.
If you're migrating from v1.x, read the full migration guide instead.
$client->getTasks() and $index->getTasks() now return a TaskResults object.
// Before (v1.x)
$tasks = $client->getTasks();
$results = $tasks['results']; // Accessing as array
// After (v2.x)
$tasks = $client->getTasks(); // Returns TaskResults
$results = $tasks->getResults(); // Returns an array of Task objectsAdditionally
all() method now returns an array of Task objects.TaskResults class is now finalTask and implement ArrayAccess (backward compatibility) (#863) @norkunasThanks to @Strift, @norkunas and dependabot[bot]! 🎉
See full changelog: v2.0.0-beta.3...v2.0.0-beta.5
Warning This release was incorrectly tagged from the wrong branch . Please use v2.0.0-beta.5 instead.
Warning
This release was incorrectly tagged from the wrong branch.
Please use v2.0.0-beta.5 instead.
Fix PHP-CS-Fixer deprecation ( #830 ) @norkunas
The custom $message property has been removed from custom exceptions. Use the getMessage() method instead:
try {
// ...
} catch (\Meilisearch\Exceptions\ApiException $e) {
// Before (v1.x)
echo $e->message;
// After (v2.x)
echo $e->getMessage();
}Also:
rethrowWithHint static method now returns a \RuntimeException instead of a generic \Exception.Thanks to @Strift and @norkunas! 🎉
See full changelog: v2.0.0-beta.2...v2.0.0-beta.3
Database stats now return a typed Stats object
Stats object$stats = $client->stats();
// Before (v1.x) - accessing stats as array
$databaseSize = $response['databaseSize'];
$usedDatabaseSize = $response['usedDatabaseSize'];
// etc...
// After (v2.x) - use getter methods
$databaseSize = $stats->getDatabaseSize();
$usedDatabaseSize = $stats->getUsedDatabaseSize();Version object$version = $client->version();
// Before (v1.x) - access as array
$commitSha = $version['commitSha'];
$commitDate = $version['commitDate']; // String
$pkgVersion = $version['pkgVersion'];
// After (v2.x) - use getter methods
$commitSha = $version->getCommitSha();
$commitDate = $version->getCommitDate(); // \DateTimeImmutable
$pkgVersion = $version->getPkgVersion();MeiliSearch namespaceWe removed MeiliSearch (capital S) namespace.
// Before (v1.x) - MeiliSearch with capital S
use MeiliSearch\Client;
// After (v2.x) - Meilisearch without capital S
use Meilisearch\Client;Indexes::parseDate() public methodThis only affects you if you were using this utility method directly.
// Before (v1.x) - If you used this method in your code
$dateTime = \Meilisearch\Endpoints\Indexes::parseDate('2021-01-01T01:23:45.123456Z');
// After (v2.x) - Use native PHP instead
$dateTime = new \DateTimeImmutable('2021-01-01T01:23:45.123456Z');Stats object (#823) @norkunasVersion object (#821) @norkunasThanks to @Strift, @bpolaszek, @dependabot[bot], @norkunas, @tacman, and @walkwizus! 🎉
See full changelog: v2.0.0-beta.1...v2.0.0-beta.2
While we recommend against production usage due to breaking changes, the code is stable. Please consider whether you can afford the potential upcoming…
While we recommend against production usage due to breaking changes, the code is stable. Please consider whether you can afford the potential upcoming breaking changes before upgrading.
This introduces two changes:
wait(int $timeoutInMs = 5000, int $intervalInMs = 50): Task methodAwaiting tasks:
// Before
$promise = $this->client->createIndex('new-index', ['primaryKey' => 'objectID']);
$this->index->waitForTask($promise['taskUid']);
// After
$this->client->createIndex('new-index', ['primaryKey' => 'objectID'])->wait();Asserting task status:
// Before
$task = $this->client->getTask($taskUid);
if ($task['status'] === 'succeeded') {
// do something
}
// After
if ($task->getStatus() === TaskStatus::Succeeded) {
// do something
}Asserting task types:
// Before
$task = $this->client->getTask($taskUid);
if ($task['type'] === 'indexCreation') {
// do something
}
// After
$task = $this->client->getTask($taskUid);
if ($task->getType() === TaskType::IndexCreation) {
// do something
}Before: catching SDK-specific JSON exceptions
<?php
try {
$client->index('books')->addDocuments([["title" => "\xB1\x31"]]);
} catch (JsonEncodingException | JsonDecodingException $e) {
// handle JSON errors
}After: catching native PHP JsonException
<?php
try {
$client->index('books')->addDocuments([["title" => "\xB1\x31"]]);
} catch (\JsonException $e) {
// handle JSON errors
}documents endpoint (#779) @bpolaszekphp-version in matrix (#792) @StriftThanks to @Strift, @bpolaszek, and @norkunas! 🎉
See full changelog: v1.16.0...v2.0.0-beta.1
Add Dynamic Search Rules ( #942 ) @Junaid-PK
Thanks to @Junaid-PK, @Strift, @dependabot[bot] and dependabot[bot]! 🎉
See full changelog: v1.16.1...v1.17.0
This PR adds support for sorting to the documents endpoint .
This PR adds support for sorting to the documents endpoint.
Thanks to @Strift, and dependabot[bot]! 🎉
See full changelog: v1.16.0...v1.16.1
This release makes the SDK compatible with features release in Meilisearch 1.16 .
This release makes the SDK compatible with features release in Meilisearch 1.16.
retrieveVectors (#777) @bpolaszekThanks again to @Strift, @bpolaszek, @brunoocasali, and @norkunas! 🎉
Nothing published for this version
Compare
Compare
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →