
August 12, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
If your application’s database queries are slowing down as content grows, implementing the Laravel Meilisearch Integration Complete Guide is often the most effective performance upgrade you can make. Traditional MySQL LIKE queries fail at scale, forcing developers to choose between complex Elasticsearch clusters or inadequate database hacks. Meilisearch offers a middle ground: a dedicated, typo-tolerant search engine that integrates natively with Laravel Scout without the operational overhead of Java-based alternatives.
meilisearch/meilisearch-php and laravel/scout via Composer, setting SCOUT_DRIVER=meilisearch in your environment, and making models searchable. This stack delivers sub-millisecond full-text search with minimal configuration for Laravel 12 applications.How do you install and configure Laravel Meilisearch integration?
Setting up this integration starts with getting both the PHP client and the search daemon running correctly. Before beginning, ensure your server runs PHP 8.2 or higher, as required by Laravel 12 and the latest Meilisearch SDKs. For teams evaluating Laravel developer expertise in Nepal, proficiency with this specific search stack has become a key differentiator for modern SaaS and e-commerce projects.
Installing dependencies and the Meilisearch binary
First, install the Laravel Scout package and the official Meilisearch PHP SDK. Do not use community wrappers; the official SDK tracks API changes closely.
composer require laravel/scout meilisearch/meilisearch-php http-interop/http-factory-guzzle Next, publish the Scout configuration file. This creates config/scout.php, where you will define driver settings, queue options, and index prefixes.
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" On Ubuntu 22.04 or 24.04 servers, install the Meilisearch binary directly rather than using Docker for single-server deployments. Direct binaries reduce memory overhead and simplify systemd management.
curl -L https://install.meilisearch.com | sh
sudo mv meilisearch /usr/local/bin/
sudo chmod +x /usr/local/bin/meilisearch Configuring environment variables
Your .env file drives the connection. Never hardcode credentials in config/scout.php. Use the master key only during development or initial setup; generate a tenant-specific API key for production applications.
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=your-master-key-here
SCOUT_QUEUE=true
SCOUT_PREFIX=prod_app_ The SCOUT_PREFIX is critical when multiple environments share a single Meilisearch instance. Without it, staging deployments will overwrite production indices. I have debugged this exact issue on shared EC2 infrastructure where sister sites like notarykathmandu.com and translationnepal.com run on the same box.
How do you make Eloquent models searchable with Scout?
Once configured, making models searchable requires adding the Searchable trait and defining what data gets indexed. This is where most implementations fail — developers index everything, bloating the search payload and slowing relevance ranking.
Adding the Searchable trait and customizing data
Add the trait to any Eloquent model. Override toSearchableArray() to control exactly which attributes reach Meilisearch. Only include fields users actually search or filter by.
use Laravel\Scout\Searchable;
class LegalDocument extends Model
{
use Searchable;
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'summary' => $this->summary,
'category' => $this->category,
'published_at' => $this->published_at->timestamp,
'author_name' => $this->author->name,
];
}
public function shouldBeSearchable(): bool
{
return $this->is_published && !is_null($this->published_at);
}
} The shouldBeSearchable() method prevents draft or archived records from polluting search results. On legal-tech portals like Court Marriage In Nepal, this ensures only current, valid legal information appears in public searches while keeping administrative drafts accessible through separate admin endpoints.
Bulk importing existing records
For existing datasets, use the Artisan import command. This chunks records automatically to prevent memory exhaustion on large tables.
php artisan scout:import "App\Models\LegalDocument" If you need to reindex after changing toSearchableArray(), flush first then reimport. There is no incremental update mechanism for schema changes.
php artisan scout:flush "App\Models\LegalDocument"
php artisan scout:import "App\Models\LegalDocument" How do you configure filterable and sortable attributes in Meilisearch?
Meilisearch does not allow filtering or sorting on arbitrary fields by default. You must explicitly declare filterable and sortable attributes. This security-by-design choice prevents accidental exposure of sensitive data through search parameters.
Defining index settings programmatically
Create an Artisan command or migration to configure index settings. Do not rely on manual dashboard configuration; infrastructure-as-code ensures consistency across environments.
use Meilisearch\Client;
$client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key'));
$index = $client->index(config('scout.prefix') . 'legal_documents');
$index->updateSettings([
'filterableAttributes' => ['category', 'published_at', 'author_name'],
'sortableAttributes' => ['published_at', 'title'],
'searchableAttributes' => ['title', 'summary', 'author_name'],
'displayedAttributes' => ['id', 'title', 'summary', 'category', 'published_at'],
'typoTolerance' => [
'enabled' => true,
'minWordSizeForTypos' => ['oneTypo' => 5, 'twoTypos' => 9],
],
]); Note that searchableAttributes controls relevance ranking order. Fields listed first carry more weight. For Nepali-language content, consider adding custom stop words since Meilisearch’s default English stop words won’t apply to Devanagari script.
How does Meilisearch compare to Elasticsearch for Laravel projects?
Choosing between Meilisearch and Elasticsearch depends entirely on your operational capacity and search requirements. Both integrate with Scout, but their trade-offs differ significantly.
| Criteria | Meilisearch | Elasticsearch |
|---|---|---|
| Setup Complexity | Single binary, zero config | JVM tuning, cluster management |
| Memory Footprint | ~200MB base + index size | ~1GB+ JVM heap minimum |
| Typo Tolerance | Built-in, automatic | Requires fuzzy query config |
| Multi-language | Good, limited tokenization | Excellent analyzers per language |
| Aggregations | Basic faceting only | Full aggregation framework |
| Horizontal Scaling | Limited (single-node primary) | Native sharding & replication |
| Laravel Scout Support | First-class driver | First-class driver |
| Best For | SaaS, e-commerce, docs | Log analytics, massive datasets |
For most Laravel applications under 10 million documents, Meilisearch wins on operational simplicity. I have migrated several WooCommerce and custom Laravel stores from Elasticsearch to Meilisearch specifically because clients could not justify dedicated DevOps time for JVM tuning. However, if you need complex aggregations or are processing terabytes of log data, Elasticsearch remains the correct tool. Teams exploring why Laravel suits Nepali businesses often find Meilisearch aligns better with local infrastructure constraints and smaller engineering teams.
How do you deploy Meilisearch in production securely?
Running Meilisearch in production requires securing the HTTP endpoint, managing persistence, and integrating with your deployment pipeline. Never expose port 7700 publicly without authentication.
Systemd service and reverse proxy
Create a systemd unit file for automatic restarts and log management. Bind Meilisearch to localhost only and front it with Nginx for SSL termination.
[Unit]
Description=Meilisearch Search Engine
After=network.target
[Service]
Type=simple
User=meilisearch
Group=meilisearch
ExecStart=/usr/local/bin/meilisearch --db-path /var/lib/meilisearch/data --master-key YOUR_MASTER_KEY
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target In Nginx, proxy requests and enforce rate limiting. Meilisearch has no built-in rate limiter, so abuse protection must happen at the reverse proxy layer.
server {
listen 443 ssl;
server_name search.yourdomain.com;
location / {
limit_req zone=search burst=20 nodelay;
proxy_pass http://127.0.0.1:7700;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
} Backup and disaster recovery
Meilisearch stores data in /var/lib/meilisearch/data. Schedule regular snapshots using the built-in dump API rather than filesystem copies, which can corrupt active indices.
curl -X POST http://127.0.0.1:7700/dumps \
-H "Authorization: Bearer YOUR_MASTER_KEY" Store dumps off-server. On projects using Deployer 7 with GitLab CI, I include a pre-deploy hook that triggers a dump and uploads it to S3 before swapping release symlinks. This ensures rollback capability even if a deployment corrupts index state.
How do you handle advanced search patterns and performance tuning?
Basic full-text search works out of the box, but production applications require faceted navigation, synonym handling, and query optimization. These features distinguish toy demos from systems that actually convert users.
Implementing faceted search
Facets require both filterable attribute configuration and explicit facet distribution requests. Always request facets server-side; client-side faceting on large result sets kills performance.
$results = LegalDocument::search('marriage registration')
->withFilters([
'category = "Family Law"',
'published_at > 1672531200',
])
->withFacets(['category', 'author_name'])
->get();
// Access facet counts in Blade
@foreach ($results->facets['category'] as $value => $count)
<label>{{ $value }} ({{ $count }})</label>
@endforeach Synonyms and language considerations
Nepali legal terminology often has multiple valid transliterations. Configure synonyms to capture these variations without duplicating content.
$index->updateSynonyms([
'bibaha' => ['marriage', 'bihe', 'विवाह'],
'sampatti' => ['property', 'assets', 'सम्पत्ति'],
'adalat' => ['court', 'tribunal', 'अदालत'],
]); For applications serving both Nepali and English speakers, maintain parallel synonym groups. Test thoroughly — incorrect synonyms create false positives that erode user trust faster than missing results.
Performance monitoring and queue management
Always enable SCOUT_QUEUE=true in production. Synchronous indexing blocks HTTP responses and creates cascading failures under load. Monitor queue depth separately from application metrics; search index lag is invisible to standard APM tools.
Set appropriate chunk sizes in config/scout.php. Default 500-record chunks work for most cases, but wide models with many relationships may need 100–200 to prevent timeout during bulk imports. Profile actual indexing time before adjusting.
Laravel Meilisearch Integration Complete Guide Next Steps
This Laravel Meilisearch Integration Complete Guide covers the foundation, but search quality is iterative. Start with basic indexing, measure actual user queries through Meilisearch analytics, then refine synonyms and attribute weights based on real behavior rather than assumptions. For teams needing hands-on implementation support or architecture review for search-heavy Laravel applications, reach out through my contact page to discuss your specific requirements. Whether you are building a legal-tech portal, an e-commerce catalog, or a SaaS knowledge base, getting search right early prevents costly rewrites later.



