meilisearch/meilisearch-laravel-scout
Official Meilisearch driver for Laravel Scout. Make your Eloquent models instantly searchable with fast, typo-tolerant full-text search, filtering, sorting, custom ranking rules, and simple index configuration—all through familiar Scout model methods.
Verdict up front: This is an archived, pre-1.0 package with a last release dated 2021-03-10. The scoring signal (460 stars, 1.825) is consistent with a legacy artifact rather than a live dependency choice. A TPM should not approve this as a new dependency for anything but a maintenance-mode application already locked to the 2020–2021 Laravel/Meilisearch generation. The realistic framing is a migration/exit assessment, not an adoption assessment.
Architecture fit: Where it fits, it fits well. It is the official Laravel Scout driver for Meilisearch, so the architectural shape is the standard, well-understood one: Eloquent model → Searchable trait → Scout → queued indexing → Meilisearch index → search() builder reads. Search is a separate service with asynchronous index writes, which is the right pattern for read-heavy product surfaces (catalog, listings, content, docs) and the wrong one where search results must be transactionally consistent with the database. Because indexing is queue-driven, the coupling to existing infrastructure is small: it consumes a queue worker and a new network dependency, and it does not restructure the application.
Integration feasibility: Mechanically low effort. Composer install, publish Scout config, set SCOUT_DRIVER=meilisearch plus host/key env, add the trait and a flat toSearchableArray() to one model, run scout:import, verify with Model::search('x')->get(). Realistic effort for a competent Laravel developer: days for a pilot on one model, not weeks. The feasibility problem is not the code — it is the version envelope. A 2021-era driver pins meilisearch/meilisearch-php at ^0.17, which targets roughly Meilisearch server 0.21+ and the Laravel 6–8 / Scout 8 era. On a current Laravel 10/11 stack this will almost certainly fail dependency resolution or require abandoned-package overrides in composer.json. That is the gating question, and it should be answered by a spike, not by reading.
Technical risk — rated HIGH overall, broken down as:
meilisearch-php 0.16.0 → 0.17.0) with a one-line changelog and no upstream behavior notes. Any team inheriting this must read the client's changelog, not the package's.maxTotalHits pagination caps, and index drift are all footguns that produce plausible-looking wrong results rather than crashes — the worst failure class for a product.Key questions (these are the decision gates):
meilisearch-php (or shipped a successor package)? If yes, this assessment converts from "adopt" to "plan the replacement" and the work is a migration ticket, not a dependency review.^0.17 of the Meilisearch client resolve against them without --ignore-platform-reqs or abandoned-package flags?Stack fit: Fits a conventional Laravel app with Scout, a queue worker, and a containerized Meilisearch service. Development can be fully local via Docker, which keeps onboarding cheap. Fit is poor where search must be strongly consistent with Postgres/MySQL writes, where the search index must be tenant-isolated at the engine level, or where the platform team mandates only actively maintained first-party dependencies.
Recommended path — treat as a bridge, not a foundation:
meilisearch-php (or a newer official package). If it does, do not introduce this archived package; integrate the current client directly and skip the migration debt entirely. This is the single highest-leverage step and costs an afternoon.Meilisearch\Client from the container so retry/backoff, task polling, and admin operations live in our code, not in calls scattered across models. This is what makes the eventual exit a config change rather than a refactor.Migration path (if already on it): Shadow-index and cut over rather than in-place. Create environment-namespaced indices via searchableAs() (posts_staging / posts_production) — this alone prevents the most common cross-environment incident. Define settings as code (filterableAttributes, sortableAttributes, rankingRules, synonyms) in an idempotent command, run scout:flush → scout:import → verify document counts, and treat reindex as a deployable operation with a runbook, not a tinker session.
Compatibility: Validate three axes independently before merging: (a) PHP/Laravel/Scout constraints against our lockfile; (b) meilisearch-php 0.17 against the running server version; (c) our index settings against the server's accepted settings schema. Note the transitive pin: if the application already requires meilisearch-php elsewhere, this package will force ^0.17 and can conflict — check composer why before touching the lockfile. Also account for task-based async writes: index mutations return task UIDs, so tests that write-then-read will flake unless they poll.
Sequencing: (1) replacement-feasibility spike → (2) one-model pilot in an ephemeral environment → (3) staging with representative data volume and index settings applied → (4) search regression suite (query relevance, filters, pagination, empty results, Meilisearch-down, queue backlog) → (5) canary or shadow index → (6) full cutover with a documented rollback to the prior package/client/server versions and a reindex plan.
Scope discipline: Keep the first release to one model and one query path. Do not return $this->toArray() from toSearchableArray() — relations and timestamps inflate the index and trip document rules. Declare filterable attributes before the first filtered query; where() on a non-filterable attribute fails or silently returns nothing depending on server version.
Maintenance: This is the dominant cost and it is not reducible by good engineering. An archived package accrues compatibility debt monotonically: no patches, no security advisories, no upstream fixes when a PHP minor or Laravel release breaks it. Budget an explicit, recurring line item for "search dependency modernization" — and plan for the eventual forced migration as a scheduled project rather than an incident. Pin versions in composer.lock, prohibit auto-merge, and require changelog review of the client on every dependency touch. Assign a named owner for search configuration, index settings, and upgrade decisions; unowned search infrastructure is where stale results hide.
Support: There is no vendor support path. Upstream is archived; the community surface (issues, docs) is frozen at 2021. Internal runbooks are the only support asset — the team must document index topology, reindex procedure, settings-as-code location, and rollback steps itself. Treat any external documentation as historical reference only.
Scaling: Scaling is a Meilisearch operations problem more than a Laravel one: index size versus memory limits, reindex duration inside deploy windows, queue throughput versus write volume, and query-pattern cost. Two concrete limits to instrument early: Meilisearch's maxTotalHits (default ~1000) will silently truncate deep pagination unless raised explicitly in settings, and index growth will eventually exceed a single node's memory — plan the reindex window and topology before that becomes urgent. Set SCOUT_QUEUE=true in production; synchronous indexing inside HTTP requests is acceptable locally and lethal under bulk writes.
Failure modes to plan for:
LIKE queries, a cached results page, or an explicit "search unavailable" state. This is a product decision, not an engineering one.scout:import for affected models into the post-deploy step.shouldBeSearchable() or the deleted/forceDeleted events are handled. Verify with a real delete, not a code read.scout:status. Expect engineers to use Model::search('')->raw() or hit /indexes/{uid}/documents directly; document this so it isn't rediscovered each time.Ramp-up: A Laravel developer reaches productive use of Scout indexing in a day or two; relevance tuning, index settings, and Meilisearch operations take meaningfully longer and are the actual skill gap. Budget one to two sprints for a pilot, staging validation, runbook creation, and a search regression suite — and note that this estimate assumes the replacement-feasibility spike comes back negative. If it comes back positive (driver now lives in the maintained client), redirect that effort into the current-package integration and skip this dependency entirely.
How can I help you explore Laravel packages today?