Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Meilisearch Laravel Package

eelcol/laravel-meilisearch

eelcol/laravel-meilisearch integrates Meilisearch with Laravel for fast, typo-tolerant full-text search. Index Eloquent models, define searchable attributes, and query results through a simple, fluent API.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin, opinionated wrapper around the official meilisearch-php client, so the mental model is: "Meilisearch does the searching, Laravel models get mirrored into an index." Start there.

  1. Install and configure. Add eelcol/laravel-meilisearch via Composer, then publish the config (typically php artisan vendor:publish --tag=meilisearch). You end up with config/meilisearch.php containing the host, key, and — importantly — an index-settings block that maps each index name to its searchable/filterable/sortable attributes. Put MEILISEARCH_HOST and MEILISEARCH_KEY in .env; run a local Meilisearch (docker run -p 7700:7700 getmeili/meilisearch) for day-to-day work.
  2. Where to look first. Read the published config before touching models. It defines the contract: which model maps to which index, and which fields are searchable, filterable, and sortable. Almost every "why doesn't my filter work" question traces back to this file.
  3. First use case. Make a model searchable by implementing the package's Searchable interface and using its trait, define searchableAs() (must match the index key in config), toSearchableArray(), and the settings method the trait expects. Then run the import/sync artisan command the package ships with (php artisan meilisearch:import, and the settings/refresh commands) to push data and index configuration. Finally MyModel::search('typo tolerant query')->get() returns hydrated Eloquent models.

If you can go from "publish config" to "model returns hits" in under ten minutes, the package is doing its job — which is exactly its intended scope.

Implementation Patterns

Model-as-index pattern. The package expects one model ≈ one index. Keep toSearchableArray() flat-ish and denormalized — include related display fields (author name, category label) so search results render without N+1 queries. Meilisearch will happily index nested arrays, but filtering and sorting against nested attributes is where people get burned, so flatten deliberately.

Config-driven schema. Treat index-settings as migrations for your search schema. Whenever you add a field you want to filter on, add it to filterableAttributes and re-run the settings sync. This is the single most important habit with this package — the index settings are state, not code, and they drift unless you sync them on deploy.

Search controller / Livewire component. The typical integration is a SearchController that takes a q parameter, does Model::search($q)->where('tenant_id', $tenantId)->take(20)->get(), and returns resources. Because it returns Eloquent models, you can reuse existing API resources and policies without a translation layer — that's the main ergonomic win versus hitting the raw client.

Filtering, sorting, faceting. Use the wrapper's where() for filters (equality, IN, numeric ranges where supported), and the sortable attributes for sort. For faceted UIs, expose the facet distribution from the raw Meilisearch facade — the trait won't give you counts, so drop to Meilisearch::index('products')->search($q, ['facets' => [...]]) for that one screen.

Write-path syncing. Rely on model events for creates/updates/deletes in normal flows, but always pair it with the artisan import as a backfill. A pragmatic pattern: queue the index writes (the package supports queueing or you wrap the save observer) so a 2s Meilisearch round-trip doesn't sit in your HTTP request.

Deployment sequence. In CI/CD run, in order: settings sync → import/refresh. If you can't afford a full reimport, ship an idempotent "reindex changed models" job and only run settings sync on schema changes.

Testing. Point MEILISEARCH_HOST at a throwaway container per test run, import fixtures, assert on hit IDs/order — don't assert on full documents, they're brittle. Keep a Searchable test trait that flushes the index in setUp.

Gotchas and Tips

  • "Filters silently return nothing." Nine times out of ten the attribute isn't in filterableAttributes. Meilisearch errors loudly on some filter mismatches but not all, and stale settings from a previous sync are a classic trap. Re-sync settings before debugging your query.
  • Sorting errors on numeric fields. Numbers stored as strings sort lexicographically. Cast in toSearchableArray() and make sure the attribute is in sortableAttributes.
  • Index name drift. searchableAs() and the config key must match exactly. A typo means indexing into a phantom index while searching an empty one — and nothing complains. Log the resolved index name once during setup.
  • Sync cost on save. The default event-driven indexing is synchronous. For bulk operations (Model::insert, seeders, imports) events don't fire at all, so the index goes stale — either disable search sync during bulk work and re-import, or drive indexing explicitly.
  • Large result hydration. The trait typically resolves results by whereIn(primaryKey, [...]), so requesting thousands of hits turns into a giant IN clause. Cap with take()/pagination and be aware result order is reconstructed in PHP, not by SQL.
  • Soft deletes and visibility. If a model is soft-deletable or has a "published" flag, override the "should be searchable" hook (or equivalent) — otherwise drafts and trashed records stay in the index until a manual flush.
  • Settings are destructive-ish. Changing filterableAttributes triggers a reindex on Meilisearch's side and can be slow on big indices. Batch/plan it; don't wire it into every request or every deploy without thought.
  • Extension point. For anything the trait doesn't cover (geo search, vector/hybrid, custom ranking rules, multi-search), reach for the Meilisearch facade and the raw client — the package is a wrapper, not a cage, and mixing raw calls with model search is expected.
  • Version coupling. Meilisearch's own API has moved fast (v1.x); confirm the package's pinned meilisearch-php version matches your server version before upgrading either. A mismatched client/server is a confusing class of failure.
  • Low bus factor. With ~15 stars and no dependents, expect to read the source when something is ambiguous — it's small enough to audit in an afternoon, and vendoring/patching a method locally is a realistic fallback if you hit an edge case. Weigh that against Scout if you need a larger community and queue/batching batteries included.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console