Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Laravel Meilisearch Integration Complete Guide

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.

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.

Laravel App.env VariablesSCOUT_DRIVERMEILISEARCH_HOSTMEILISEARCH_KEYSCOUT_PREFIXScout Enginemeilisearch-php SDKHTTP Client (Guzzle)Index ManagementSearch QueriesMeilisearchPort 7700Inverted IndexTypo ToleranceFilterable Attributes
Configuration flow for Laravel Meilisearch Integration Complete Guide showing how environment variables connect the application to the search engine

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.

Meilisearch Index SettingsSearchableRelevance Rankingtitle (highest)summaryauthor_nameUsed for query matchingFilterableWHERE Clausescategorypublished_atauthor_nameMust be declared explicitlySortableORDER BY Clausespublished_attitleNumeric/date fields preferred
Attribute types in Laravel Meilisearch Integration Complete Guide: searchable affects relevance, filterable enables constraints, sortable controls ordering

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.

CriteriaMeilisearchElasticsearch
Setup ComplexitySingle binary, zero configJVM tuning, cluster management
Memory Footprint~200MB base + index size~1GB+ JVM heap minimum
Typo ToleranceBuilt-in, automaticRequires fuzzy query config
Multi-languageGood, limited tokenizationExcellent analyzers per language
AggregationsBasic faceting onlyFull aggregation framework
Horizontal ScalingLimited (single-node primary)Native sharding & replication
Laravel Scout SupportFirst-class driverFirst-class driver
Best ForSaaS, e-commerce, docsLog 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.

Laravel AppScout QueuePHP-FPMNginxSSL TerminationRate LimitingAuth HeadersMeilisearchlocalhost:7700Systemd ManagedPersistent StorageS3 BackupScheduled DumpsPre-deploy Hook
Secure production topology for Laravel Meilisearch Integration Complete Guide with Nginx reverse proxy and automated S3 backups

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.

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.

Frequently Asked Questions

Laravel 12 requires PHP 8.2 or higher. Meilisearch PHP SDK v1.x supports PHP 8.2 through 8.4. Always verify your composer.json platform config matches your production server PHP binary to avoid deployment failures.

Meilisearch is self-hosted and free, eliminating per-record costs that make Algolia expensive at scale. In my experience building search for legal-tech portals, Meilisearch offers comparable relevance with full data sovereignty, crucial for Nepali clients handling sensitive case information who cannot use cloud-hosted indexes.

A basic Meilisearch instance runs comfortably on a 2GB RAM VPS costing Rs 1,500–2,500 monthly (~USD 11–19). Unlike Algolia's usage-based pricing, this flat rate covers unlimited records and queries, making it predictable for Nepal-based businesses budgeting in NPR.

Run composer require laravel/scout meilisearch/meilisearch-php then publish the scout config. Set SCOUT_DRIVER=meilisearch and MEILISEARCH_HOST in your .env file. Ensure the Meilisearch binary is running locally or remotely before executing php artisan scout:import to populate your initial index.

Production environments often run different Meilisearch versions or lack synchronized filterable/sortable attributes. I have debugged this repeatedly on Deployer 7 pipelines where the staging index settings drifted from production. Always define index settings explicitly in a migration or Artisan command rather than relying on auto-detection.

Yes, Livewire pairs excellently with Meilisearch for instant feedback without page reloads. On a recent trekking booking platform, I implemented debounced Livewire components querying Scout directly. This avoids exposing API keys client-side while delivering sub-100ms search responses for itinerary filtering and destination lookups.

Meilisearch supports Unicode natively but may need custom stop words for Devanagari script. Configure a dedicated index with specific tokenizer rules and stop word lists for Nepali content. For legal directories containing mixed English and Nepali terms, separate indices per language often yield better relevance than forcing a single multilingual configuration.

Meilisearch supports multi-tenant isolation via tenant tokens and API key restrictions. When building client portals for law firms, I enforce document-level security by embedding user IDs in searchable attributes and generating scoped JWTs. Never store unencrypted PII in the index; treat it as a read-only projection of your secured primary database.

Laravel Scout fails gracefully but search functionality becomes unavailable. Implement a fallback mechanism using database LIKE queries for critical paths. In production deployments on shared EC2 infrastructure, I configure health checks in GitLab CI and use systemd restart policies to ensure Meilisearch recovers automatically after unexpected crashes or memory exhaustion.

Batch imports using chunked processing prevents memory spikes. Disable ranking updates during bulk imports via the MEILISEARCH_DISABLE_RANKING environment variable, then re-enable after completion. For e-commerce catalogs with thousands of SKUs, schedule reindexing during off-peak hours using Laravel's task scheduler to avoid impacting live search latency.

Minor version upgrades rarely require rebuilding, but major versions may change internal storage formats. Always test upgrades in staging first. After upgrading, run php artisan scout:flush followed by scout:import to ensure compatibility. Keep backups of your data directory before any upgrade to enable quick rollback if corruption occurs.

Verify the model uses Searchable trait, data exists in the index via curl GET /indexes/{name}/documents, and filterable attributes are configured correctly. Common issues include mismatched attribute names between Eloquent and Meilisearch schema, or missing composite primary keys. Check Laravel logs for Scout exceptions and Meilisearch task queue for failed indexing operations.

Meilisearch excels at typo-tolerant, faceted search but lacks transactional guarantees. Use it for discovery interfaces while keeping MySQL as the source of truth. For order management or financial reporting requiring ACID compliance, stick with relational queries. I reserve Meilisearch strictly for user-facing search experiences where relevance matters more than absolute consistency.

Prefix index names with environment variables like MEILISEARCH_INDEX_PREFIX=prod_ to prevent cross-contamination. Define all filterable, sortable, and searchable attributes in version-controlled configuration files applied via Artisan commands during deployment. This ensures staging and production schemas stay synchronized, avoiding subtle bugs when promoting code through CI/CD pipelines.

Expose the /health and /stats endpoints to your monitoring stack. Track index size, task queue length, and response latency. Set alerts for disk usage exceeding 80% since Meilisearch stops accepting writes when full. On Ubuntu servers, I integrate these metrics with Prometheus and configure fail2ban to protect the HTTP endpoint from abuse.

Share this article

Quick Contact Options
Choose how you want to connect me: