lancodev/filament-meilisearch
Filament plugin that connects your admin panels to Meilisearch, adding fast, typo-tolerant full-text search to resources and tables with minimal setup.
lancodev/filament-meilisearch wires Laravel Scout's Meilisearch engine into Filament's global search, so the top-bar search (and any plugin-provided search UI) queries Meilisearch instead of walking your Eloquent resources.
Requirements (as of v2.0.1):
laravel/scout installed and configuredMinimal setup:
composer require lancodev/filament-meilisearchphp artisan vendor:publish --tag="filament-meilisearch-config".env, point Scout at Meilisearch:
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=<master-or-admin-key>
PanelProvider:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentMeilisearchPlugin::make());
}
Laravel\Scout\Searchable to the models backing your resources and run php artisan scout:import "App\Models\Post".Where to look first: the published config/filament-meilisearch.php (host/key/index naming and the search toggle) and the plugin's make() method in your panel provider — that is where per-panel behaviour is decided. Then check the package README's resource examples to confirm how a Filament resource opts into the external index.
First use case: replace Filament's default getGlobalSearchResults() DB LIKE queries on a large Post/Order table with Meilisearch-backed results — you get typo tolerance and relevance ranking for free, usually with no changes to your resource table columns.
Per-resource opt-in. Typically a resource declares the searchable model and the columns/labels shown in results; keep that mapping in the resource rather than in the plugin so each panel can differ. Return lightweight result DTOs from the resource's global-search method and let the plugin handle the query.
Index shape first, UI second. Define toSearchableArray() deliberately — it is your search document, not your model. Flatten relations, strip large HTML blobs, and expose only fields you actually display or filter on.
Filterable attributes are a contract. Any where()/facet you apply at query time must exist in Meilisearch's filterableAttributes. Drive this from scout:sync-index-settings (Scout's searchableAs() plus the engine's index-settings config) so a fresh environment reproduces the same index as production.
Panels and tenancy. For multi-tenant apps, apply a tenant filter at query time (e.g. a where('tenant_id', ...) on the search) and add tenant_id to filterable attributes. Do not rely on separate indexes per tenant unless you have a strong isolation requirement — it multiplies index-management work.
Indexing pipeline. Keep SCOUT_QUEUE=true in production and index through Horizon/your queue worker; run scout:import on deploy for new models and after any toSearchableArray() change. For very large tables use makeAllSearchableUsing() with eager loads to avoid N+1 during import.
Local development. Run Meilisearch via Sail/Compose, and make seeding part of your setup script (scout:import after migrate:fresh --seed). Keep a .env.testing pointing at a disposable instance so feature tests exercise real ranking behaviour rather than a mocked engine.
Progressive rollout. Leave Filament's built-in global search enabled for small resources and route only the heavy ones through Meilisearch — the plugin and the default search coexist fine per resource.
^1.0 for v3 panels and upgrade deliberately — the plugin registration API differs between major versions.- and _. UUIDs and integer keys are fine, but prefixed/composite keys (post:1) will be rejected — override getScoutKey() if your model uses one.filterableAttributes and searchableAttributes live in the index, not in code. Re-run the settings sync and re-import; restart the Meilisearch container only if settings updates fail.searchableAttributes in priority order and consider attributesToSearchOn per query.Searchable is configured to remove them — verify your delete()/restore() observers and that queue workers are running. php artisan scout:status and scout:flush are your debugging levers.minWordSizeForTypos defaults mean 3–4 character queries get no tolerance; tune it if users search SKUs or codes.GET /indexes/<index>/search?q=...) → confirm the document shape → confirm the plugin's query → check Filament resource visibility/authorisation (canViewAny, canGloballySearch) before assuming a search bug.filament-hidden class on the banner image; there is no migration work from v2.0.0. Treat this as a safe patch bump.How can I help you explore Laravel packages today?