Supercharged Search with Laravel Scout and Meilisearch

· 4 min read

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:

  1. Performance: They perform full table scans, becoming exponentially slower as data grows
  2. No typo tolerance: "Jonh" won't match "John"
  3. No relevance ranking: Results aren't sorted by how well they match
  4. 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

  1. Install Scout:
composer require laravel/scout
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
  1. Install Meilisearch Driver:
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
  1. 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

  1. Index only searchable content: Don't index passwords or sensitive data
  2. Use queue for large datasets: Prevent request timeouts
  3. Configure stop words: Exclude common words like "the", "and"
  4. Set up synonyms: Map "JS" to "JavaScript"
  5. 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.

Comments