laravel/scout
Laravel Scout adds driver-based full-text search to Eloquent models, automatically syncing model changes to indexes. Supports Algolia, Meilisearch, and Typesense.
Architecture fit
Searchable trait and model observers — no new service layer, no rewrite of the read model. For any Laravel monolith or modular monolith, this is the lowest-friction path to search.Laravel\Scout\Builder (a fluent, Eloquent-like API), and the engine is a config value. That makes the engine choice a deferrable, reversible decision — the single most important property for a TPM scoping this work.Integration feasibility
composer require laravel/scout, publish config, add trait + toSearchableArray() to N models, set driver via env, run scout:import. A single engineer can deliver a working vertical slice in days, not weeks.toSearchableArray() is the real design work: it is the denormalization contract. Every relationship flattened into the index is a future reindex trigger.whereIn/whereNotIn, pagination correctness across engines, transaction-commit ordering (afterCommit), custom index names, settings sync, and Laravel 12 / PHP 8.4 support. This is a maintained package on the framework's release cadence, not an abandoned one.Technical risk
whereIn/whereNotIn, boolean filter formatting, pagination counts, and settings sync have all required engine-specific fixes (multiple Typesense pagination and filter bugs in the 10.11–10.14 range; Algolia client v2/v4 churn). Any filter the team leans on must be validated per engine, not assumed.scout:import, not after.Key questions
LIKE search, empty results, or hard error?Stack fit
Model::search() idiom, so product engineers don't learn a second query language; the escape hatch is __call() pass-through to the underlying client for engine-specific features.Migration path
Searchable trait, toSearchableArray(), and the search endpoint against the Database engine. This proves the UX, the payload shape, and the API contract with zero new infrastructure and zero vendor commitment.scout:import are the only deltas.SearchService wrapper over Laravel\Scout\Builder so that the ~10% of call sites using engine-specific filters are isolated.Compatibility
| Engine | Infra owned | Data residency | Feature depth | Cost shape | Recommended phase |
|---|---|---|---|---|---|
| Database | None | In-DB | Low (no real relevance) | Free | Phase 0 |
| Collection | None | In-process | Test-only | Free | CI/tests |
| Meilisearch | Self | In-VPC | High | Compute + ops | Phase 1 |
| Typesense | Self | In-VPC | High | Compute + ops | Phase 1 |
| Algolia | Vendor | Vendor | Highest | Per record/op | Phase 2 (conditional) |
Sequencing
toSearchableArray() + Database engine behind the search endpoint; instrument relevance and zero-result rate from day one.scout:import with tuned chunk size, measure index size, import duration, and query latency.Maintenance
toSearchableArray() is a reindex event. Budget for a reindex runbook and a scheduled full reindex (e.g. weekly) as routine hygiene, not an incident response.Support
Scaling
scout:import on large tables is memory- and time-sensitive; chunk size tuning and off-peak scheduling are required operational parameters, not defaults.Failure modes
upsert, DB::table() writes bypass Eloquent entirely). This is the most common real-world failure and is invisible without reconciliation. Any bulk-write path must be enumerated and explicitly handled.Ramp-up
How can I help you explore Laravel packages today?