Supercharged Search with Laravel Scout and Meilisearch
User::where('name', 'like', '%john%')->get() is fine for 100 users.
For 100,000 users, it's slow.
And if the user types "Jonh", it returns nothing.
Laravel Scout provides a driver-based solution for adding full-text search to your models. Meilisearch is an open-source, ultra-fast search engine that pairs perfectly with Laravel.
Why Full-Text Search Matters
Traditional SQL LIKE queries have several limitations:
- Performance: They perform full table scans, becoming exponentially slower as data grows
- No typo tolerance: "Jonh" won't match "John"
- No relevance ranking: Results aren't sorted by how well they match
- No stemming: "running" won't match "run"
Full-text search engines solve all of these problems by building inverted indexes and using sophisticated algorithms.
Installation
- Install Scout:
composer require laravel/scout
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
- Install Meilisearch Driver:
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
- Configure your
.env:
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=your-master-key
Configuration
Add the Searchable trait to your model.
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
// Optional: Customize what data is indexed
public function toSearchableArray()
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => strip_tags($this->content),
'author' => $this->author->name,
'tags' => $this->tags->pluck('name')->toArray(),
'published_at' => $this->published_at?->timestamp,
];
}
// Customize the search index name
public function searchableAs(): string
{
return 'posts_index';
}
}
Running Meilisearch
The easiest way is via Laravel Sail (Docker):
# docker-compose.yml
meilisearch:
image: 'getmeili/meilisearch:latest'
ports:
- '7700:7700'
environment:
- MEILI_MASTER_KEY=your-master-key
volumes:
- 'sail-meilisearch:/meili_data'
Or install locally on macOS:
brew install meilisearch
meilisearch --master-key="your-master-key"
Indexing Data
Push your existing data to the search engine:
php artisan scout:import "App\Models\Post"
To re-index after schema changes:
php artisan scout:flush "App\Models\Post"
php artisan scout:import "App\Models\Post"
Searching
Now replace your standard queries with Scout queries:
// Standard SQL (Slow, strict)
Post::where('title', 'like', '%larvel%')->get(); // Returns nothing
// Scout (Fast, typo-tolerant)
Post::search('larvel')->get(); // Returns 'Laravel' posts
Filters and Sorting
Scout supports filtering and sorting through Meilisearch's powerful features:
// Basic filtering
Post::search('tutorial')
->where('status', 'published')
->paginate(20);
// Multiple filters
Post::search('laravel')
->where('category_id', 5)
->where('published_at', '>', now()->subMonth()->timestamp)
->get();
Configure Filterable Attributes
To use filters, you must configure Meilisearch:
// In AppServiceProvider or a command
use Meilisearch\Client;
$client = new Client(config('scout.meilisearch.host'));
$client->index('posts_index')->updateFilterableAttributes([
'status',
'category_id',
'published_at',
'tags',
]);
$client->index('posts_index')->updateSortableAttributes([
'published_at',
'views_count',
]);
Pagination
Scout integrates seamlessly with Laravel's pagination:
$results = Post::search('laravel')->paginate(15);
// In Blade
@foreach($results as $post)
<h2>{{ $post->title }}</h2>
@endforeach
{{ $results->links() }}
Real-Time Updates
Scout automatically syncs changes to your search index:
// This automatically updates the search index
$post->update(['title' => 'New Title']);
// This removes from the search index
$post->delete();
Queueing Index Updates
For better performance, queue your index operations:
// config/scout.php
'queue' => true,
Meilisearch vs Algolia
| Feature | Meilisearch | Algolia |
|---|---|---|
| Pricing | Free (self-hosted) | Pay per search |
| Typo tolerance | ✅ | ✅ |
| Faceted search | ✅ | ✅ |
| Hosting | Self-hosted or Cloud | Managed only |
| Performance | Excellent | Excellent |
For most projects, Meilisearch offers the best balance of features and cost.
Best Practices
- Index only searchable content: Don't index passwords or sensitive data
- Use queue for large datasets: Prevent request timeouts
- Configure stop words: Exclude common words like "the", "and"
- Set up synonyms: Map "JS" to "JavaScript"
- Monitor index size: Keep your search data lean
Full-text search transforms user experience. With Scout and Meilisearch, you get enterprise-level search capabilities without the enterprise price tag.