How to Install Meilisearch on Ubuntu 24.04 VPS: Lightning-Fast Open-Source Search Engine
Search is one of those features your users only notice when it is bad. Slow autocomplete, irrelevant results, zero-tolerance for typos -- any of these will tank engagement no matter how good the rest of your product is. Meilisearch is an open-source, Rust-based search engine that solves all three problems out of the box, with a developer experience that rivals Algolia and costs you nothing beyond the VPS it runs on. This guide walks you through installing Meilisearch on an Ubuntu 24.04 VPS, from package install to a production deployment with HTTPS, tenant tokens, and automated backups.
Self-hosting search saves real money. Algolia's pricing starts around $0.50 per 1,000 search requests and scales to thousands of dollars per month for medium-traffic apps. A Meilisearch instance on a CloudCore Starter VPS handles millions of searches per month at a flat rate.
Table of Contents
What is Meilisearch?
Meilisearch is an open-source, lightning-fast, typo-tolerant search engine written in Rust. It is distributed as a single static binary -- no JVM, no Python runtime, no external dependencies -- which makes it trivially easy to deploy on any Linux server. Under the hood it uses an LMDB-backed inverted index with custom ranking rules, and it returns results in under 50 milliseconds for most datasets, even on modest hardware.
Meilisearch is designed around the concept of instant search: as the user types, results update on every keystroke. To make this feel natural, the engine ships with typo tolerance, prefix search, synonyms, and a ranking pipeline that can be reordered per index. You define searchable, filterable, and sortable attributes declaratively, and the engine handles the rest.
The feature set covers the needs of the vast majority of product, content, and documentation search use cases. You get full-text search with typo tolerance (up to 2 typos by default, configurable per query), faceted filtering (for category, price-range, status pickers), geo-search (radius and bounding-box queries using _geo attributes), multi-index federated search (query multiple indexes in one request), ranking rules (typo, words, proximity, attribute, sort, exactness), synonyms and stop words, highlighting and cropping of matched snippets, and a built-in search preview dashboard served at the root URL. Since version 1.6, Meilisearch also ships with hybrid search, combining keyword search with vector embeddings for semantic matching -- useful for RAG applications and semantic product discovery.
Typical use cases include e-commerce product search, documentation and knowledge base search, SaaS in-app search across customer data, media and article search for news sites, and embedded search for mobile apps. If you have a database table with more than a few thousand rows that users want to search through with typeahead, Meilisearch is almost certainly the right answer.
Why Self-Host Meilisearch?
Running search on your own VPS instead of paying a hosted service offers concrete advantages, especially as traffic grows:
- Predictable flat-rate pricing -- Algolia charges per search request and per indexed record. At scale, this becomes one of the largest line items in a SaaS infrastructure budget. Meilisearch on a VPS costs the same whether you handle 10,000 or 10 million searches per month.
- No per-record fees -- Algolia's record count metric penalizes apps with large catalogs or fine-grained nested documents. Self-hosted Meilisearch has no document-count limit beyond what your disk and RAM allow.
- Data sovereignty -- Your users' search queries and your indexed data never leave your infrastructure. For GDPR, HIPAA, and SOC 2 compliance, keeping search on-premises eliminates an entire class of vendor risk.
- Lower latency for colocated apps -- When your application server and Meilisearch live in the same data center (or the same machine), round-trip time drops to sub-millisecond levels. Hosted search APIs add 20-100 ms of network overhead on every query.
- Full customization -- Tune ranking rules, add custom stop words, plug in your own embeddings model for hybrid search. No vendor lock-in, no feature gating by plan tier.
- Open source -- MIT-licensed. Fork it, audit it, embed it in a commercial product. No license fees, no runtime royalties.
Cost Comparison: Self-Hosted Meilisearch vs. Algolia
| Scenario | Algolia | Meilisearch Cloud | Self-Hosted Meilisearch (VPS) |
|---|---|---|---|
| 100K records, 100K searches/mo | ~$100-200/mo | ~$30/mo | EUR 7.50/mo (flat) |
| 1M records, 1M searches/mo | ~$1,000-2,500/mo | ~$150/mo | EUR 19.99/mo (flat) |
| 10M records, 10M searches/mo | ~$5,000-15,000/mo | ~$500+/mo | EUR 49/mo (flat) |
| Search latency (p95) | 20-80 ms (edge) | 30-100 ms | 5-30 ms (same DC) |
| Data residency control | Limited | Limited | Full |
| Custom ranking rules | Yes | Yes | Yes |
| Tenant tokens | Yes | Yes | Yes |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- A domain name pointing to the server (required for HTTPS in Step 9)
- At least 2 GB of RAM for datasets up to ~1 million documents (4 GB+ recommended for production)
- At least 20 GB of free disk space (index size is typically 1.5-3x the raw JSON document size)
Recommended Plan: CloudCore Starter>
For up to ~1 million documents and steady search traffic, the CloudCore Starter plan is a great fit:>
- 4 vCPU cores
- 8 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth>
This gives Meilisearch enough memory to keep your full index mapped in RAM for sub-10ms query times, plus headroom for an application stack on the same server. For larger indexes (10M+ documents), scale up to CloudCore Professional or dedicate a separate VPS to search.
Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
Start by updating the package index and installed packages. This ensures clean dependency resolution when you add the Meilisearch apt repository.
sudo apt update && sudo apt upgrade -yInstall a few utilities you will need throughout this guide:
sudo apt install -y curl gnupg apt-transport-https ca-certificates jqIf your kernel was upgraded, reboot before continuing:
sudo rebootStep 2: Install Meilisearch
Meilisearch provides two supported installation paths on Ubuntu: the official apt repository hosted on Gemfury, or the one-line curl installer. The apt method is recommended for production because it integrates with unattended upgrades.
Option A: Install via apt (recommended)
Add the Meilisearch apt repository and install the package:
# Add the GPG key and repository echo "deb [trusted=yes] https://apt.fury.io/meilisearch/ /" | \ sudo tee /etc/apt/sources.list.d/meilisearch.list
sudo apt update sudo apt install -y meilisearch
Verify the binary is installed:
meilisearch --versionExpected output:
meilisearch 1.11.0The apt package installs the meilisearch binary to /usr/bin/meilisearch. It does not create a systemd service automatically -- you will do that in Step 4.
Option B: Install via curl (alternative)
If you prefer to pin a specific version or cannot add third-party apt repositories, use the official install script:
curl -L https://install.meilisearch.com | sh
sudo mv ./meilisearch /usr/local/bin/Verify:
/usr/local/bin/meilisearch --versionStep 3: Configure the Master Key and Environment
Meilisearch has two runtime modes: development (no auth, verbose logs) and production (authentication required, minimal logs). Always use production mode on any internet-reachable server.
Create the data directory and user
sudo useradd -r -s /bin/false -M meilisearch
sudo mkdir -p /var/lib/meilisearch/data
sudo mkdir -p /var/lib/meilisearch/dumps
sudo mkdir -p /var/lib/meilisearch/snapshots
sudo chown -R meilisearch:meilisearch /var/lib/meilisearchGenerate a strong master key
The master key is the root credential for your Meilisearch instance. Anyone with it has full admin control. Generate 48 random bytes and base64-encode them:
openssl rand -base64 48Copy the output -- you will use it in the config file. Example (do not use this exact key):
Ht3k9sQvX2mY7NpLaRb8Zf4WjC5VyT6DxH1GqE0KpM3sCreate the configuration file
Meilisearch reads settings from /etc/meilisearch.toml by default when invoked with --config-file-path. Create it:
sudo tee /etc/meilisearch.toml > /dev/null <<'EOF'
============================================================================
Meilisearch configuration
============================================================================
Master API key (REQUIRED in production). Minimum 16 bytes.
master_key = "REPLACE_WITH_YOUR_GENERATED_KEY"Runtime environment. "production" enables auth; "development" disables it.
env = "production"Address Meilisearch listens on. Keep 127.0.0.1 when using an Nginx proxy.
http_addr = "127.0.0.1:7700"Where Meilisearch stores indexes on disk.
db_path = "/var/lib/meilisearch/data"Dumps directory (portable backups).
dump_dir = "/var/lib/meilisearch/dumps"Snapshots directory (fast binary backups).
snapshot_dir = "/var/lib/meilisearch/snapshots"Enable automatic snapshots every 24 hours (in seconds).
schedule_snapshot = 86400Log level: ERROR, WARN, INFO, DEBUG, TRACE
log_level = "INFO"Max size of the indexing task queue.
max_indexing_memory = "2 GiB"
max_indexing_threads = 2
EOFReplace REPLACE_WITH_YOUR_GENERATED_KEY with the key you generated:
sudo nano /etc/meilisearch.tomlSecure the config file -- it contains the master key:
sudo chown meilisearch:meilisearch /etc/meilisearch.toml
sudo chmod 600 /etc/meilisearch.tomlAlternative: environment variables. If you prefer not to use a config file, Meilisearch accepts the same settings via env vars:MEILI_MASTER_KEY,MEILI_ENV=production,MEILI_HTTP_ADDR,MEILI_DB_PATH,MEILI_DUMP_DIR,MEILI_SNAPSHOT_DIR,MEILI_SCHEDULE_SNAPSHOT. Set them in the systemd unit'sEnvironment=directives.
Step 4: Create the systemd Service
The apt package does not ship a systemd unit file, so create one now. This ensures Meilisearch starts on boot and restarts on crash.
sudo tee /etc/systemd/system/meilisearch.service > /dev/null <<'EOF' [Unit] Description=Meilisearch search engine After=network.target Documentation=https://www.meilisearch.com/docs[Service] Type=simple User=meilisearch Group=meilisearch ExecStart=/usr/bin/meilisearch --config-file-path /etc/meilisearch.toml Restart=on-failure RestartSec=5s
Hardening
NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/lib/meilisearch LimitNOFILE=65536
[Install] WantedBy=multi-user.target EOF
If you installed Meilisearch via the curl installer (Option B in Step 2), replace /usr/bin/meilisearch with /usr/local/bin/meilisearch.
Reload systemd, then enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable meilisearch
sudo systemctl start meilisearchCheck the service status:
sudo systemctl status meilisearchExpected output (abbreviated):
● meilisearch.service - Meilisearch search engine
Loaded: loaded (/etc/systemd/system/meilisearch.service; enabled)
Active: active (running) since Wed 2026-04-16 10:00:00 UTC; 5s ago
Main PID: 1456 (meilisearch)
Tasks: 8 (limit: 9321)
Memory: 52.0M
CGroup: /system.slice/meilisearch.service
└─1456 /usr/bin/meilisearch --config-file-path /etc/meilisearch.tomlStep 5: Verify the Installation
Store your master key in a shell variable so you do not have to retype it:
export MEILI_KEY="REPLACE_WITH_YOUR_GENERATED_KEY"Ping the health endpoint -- it requires no auth:
curl http://localhost:7700/healthExpected output:
{"status":"available"}Fetch server version (requires auth in production mode):
curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/versionExpected output:
{
"commitSha": "abc1234...",
"commitDate": "2026-01-15T10:00:00Z",
"pkgVersion": "1.11.0"
}List existing indexes (should be empty):
curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/indexesExpected output:
{"results":[],"offset":0,"limit":20,"total":0}Meilisearch is running and authenticated. Next, load some data.
Step 6: Create an Index and Add Documents
Meilisearch auto-creates indexes when you add documents to them -- no separate "create index" step required. You just need to pick a primary key: the field Meilisearch uses to uniquely identify each document. If your documents have an id field, Meilisearch detects it automatically.
Add documents to a new index
Create a sample dataset of movies:
cat > /tmp/movies.json <<'EOF'
[
{"id": 1, "title": "The Matrix", "year": 1999, "genre": "Sci-Fi", "rating": 8.7},
{"id": 2, "title": "Inception", "year": 2010, "genre": "Sci-Fi", "rating": 8.8},
{"id": 3, "title": "The Dark Knight", "year": 2008, "genre": "Action", "rating": 9.0},
{"id": 4, "title": "Interstellar", "year": 2014, "genre": "Sci-Fi", "rating": 8.6},
{"id": 5, "title": "Parasite", "year": 2019, "genre": "Thriller", "rating": 8.5}
]
EOFPOST them to the movies index:
curl -X POST "http://localhost:7700/indexes/movies/documents" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary @/tmp/movies.jsonExpected output:
{
"taskUid": 0,
"indexUid": "movies",
"status": "enqueued",
"type": "documentAdditionOrUpdate",
"enqueuedAt": "2026-04-16T10:15:00Z"
}Indexing is asynchronous. Poll the task endpoint to confirm completion:
curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/tasks/0Look for "status": "succeeded" in the response. For small datasets like this one, indexing completes in milliseconds.
Run your first search
curl -X POST "http://localhost:7700/indexes/movies/search" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{"q": "matrix"}'Expected output:
{
"hits": [
{"id": 1, "title": "The Matrix", "year": 1999, "genre": "Sci-Fi", "rating": 8.7}
],
"query": "matrix",
"processingTimeMs": 1,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 1
}Try typo tolerance -- query "matirx" (typo):
curl -X POST "http://localhost:7700/indexes/movies/search" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{"q": "matirx"}'Meilisearch still returns The Matrix. That is the out-of-the-box typo tolerance at work.
Step 7: Configure Index Settings
By default, all fields are searchable, none are filterable, and none are sortable. Tuning these settings is what turns Meilisearch from "search that works" into "search that feels instant and precise."
Set searchable attributes (order matters for ranking)
curl -X PUT "http://localhost:7700/indexes/movies/settings/searchable-attributes" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '["title", "genre"]'Fields listed earlier get higher ranking weight. Here, a match in title outranks a match in genre.
Set filterable attributes
Filterable attributes enable filter expressions in search requests (e.g., year > 2010, genre = "Sci-Fi"):
curl -X PUT "http://localhost:7700/indexes/movies/settings/filterable-attributes" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '["genre", "year", "rating"]'Now you can run filtered searches:
curl -X POST "http://localhost:7700/indexes/movies/search" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{
"q": "",
"filter": "year > 2010 AND genre = \"Sci-Fi\""
}'Set sortable attributes
curl -X PUT "http://localhost:7700/indexes/movies/settings/sortable-attributes" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '["rating", "year"]'Sort results by rating descending:
curl -X POST "http://localhost:7700/indexes/movies/search" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{
"q": "",
"sort": ["rating:desc"]
}'Configure ranking rules
The default ranking pipeline is excellent for most use cases, but you can reorder or add custom rules. For example, prioritize higher-rated movies:
curl -X PUT "http://localhost:7700/indexes/movies/settings/ranking-rules" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '[
"words",
"typo",
"proximity",
"attribute",
"sort",
"exactness",
"rating:desc"
]'Add synonyms
curl -X PUT "http://localhost:7700/indexes/movies/settings/synonyms" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{
"sci-fi": ["science fiction", "scifi"],
"film": ["movie"]
}'Now searching for "science fiction" matches documents tagged "Sci-Fi".
Step 8: Manage API Keys and Tenant Tokens
The master key is too powerful to ship to a browser or embed in a mobile app. Meilisearch provides two lower-privilege credential types: API keys (scoped to specific actions and indexes) and tenant tokens (JWTs derived from an API key that add row-level filters).
List default keys
Meilisearch auto-generates two keys on first boot. List them:
curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/keys | jqYou will see:
- Default Admin API Key -- full access except managing other keys
- Default Search API Key -- search-only, safe to expose in frontend code
key value of the search key. That is what you embed in your frontend JavaScript.Create a custom scoped API key
Create a key that can only search the movies index:
curl -X POST "http://localhost:7700/keys" \
-H "Authorization: Bearer $MEILI_KEY" \
-H "Content-Type: application/json" \
--data-binary '{
"description": "Frontend search key for movies",
"actions": ["search"],
"indexes": ["movies"],
"expiresAt": "2027-01-01T00:00:00Z"
}'Tenant tokens (multi-tenant row-level security)
Tenant tokens are the killer feature for SaaS apps. They are JWTs signed with a Meilisearch API key, containing a searchRules claim that enforces a filter on every search. Each customer gets a different token, each token pins a different filter, all on a single shared index.
Generate one in Node.js using the official SDK:
import { Meilisearch } from 'meilisearch';const client = new Meilisearch({ host: 'https://search.yourdomain.com', apiKey: 'YOUR_ADMIN_KEY', });
const apiKeyUid = 'the-uid-of-a-search-api-key';
const tenantToken = await client.generateTenantToken( apiKeyUid, { movies: { filter: 'customerId = "customer_42"', }, }, { expiresAt: new Date('2026-12-31') } );
// Hand this token to customer_42's browser.
When the browser uses this token to search the movies index, Meilisearch automatically appends customerId = "customer_42" to every query. Even if the client manipulates the request, they cannot see other customers' documents.
Step 9: Set Up Nginx Reverse Proxy with TLS
Meilisearch speaks plain HTTP. Never expose it directly to the internet. Put Nginx in front of it for TLS termination, rate limiting, and optional basic auth on admin endpoints.
Install Nginx and Certbot
sudo apt install -y nginx certbot python3-certbot-nginxOpen the firewall
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw --force enableCreate the Nginx site
Replace search.yourdomain.com with your actual domain:
sudo tee /etc/nginx/sites-available/meilisearch > /dev/null <<'EOF'Rate limit search endpoints
limit_req_zone $binary_remote_addr zone=meili_search:10m rate=30r/s;server { listen 80; server_name search.yourdomain.com; return 301 https://$host$request_uri; }
server { listen 443 ssl http2; server_name search.yourdomain.com;
# SSL certs filled in by Certbot ssl_certificate /etc/letsencrypt/live/search.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/search.yourdomain.com/privkey.pem;
# Security headers add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY;
client_max_body_size 100m;
# Apply rate limit to search endpoints location ~ ^/indexes/[^/]+/search$ { limit_req zone=meili_search burst=50 nodelay; proxy_pass http://127.0.0.1:7700; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location / { proxy_pass http://127.0.0.1:7700; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300s; } } EOF
sudo ln -s /etc/nginx/sites-available/meilisearch /etc/nginx/sites-enabled/
Obtain a Let's Encrypt certificate
sudo certbot --nginx -d search.yourdomain.com
sudo nginx -t && sudo systemctl reload nginxTest end-to-end:
curl https://search.yourdomain.com/healthExpected output:
{"status":"available"}Step 10: Enable Snapshots and Dumps
Meilisearch supports two backup mechanisms. Use both.
Snapshots are fast binary copies of the data directory. They are point-in-time and tied to the exact Meilisearch version. Ideal for crash recovery.
Dumps are portable JSON exports. Slower to produce and restore, but they work across Meilisearch versions -- essential for upgrades and cross-environment migrations.
Snapshots (already enabled)
Snapshots are already scheduled every 24 hours thanks to schedule_snapshot = 86400 in /etc/meilisearch.toml. Verify they are being written:
ls -lh /var/lib/meilisearch/snapshots/Trigger an on-demand snapshot via the API:
curl -X POST -H "Authorization: Bearer $MEILI_KEY" \
http://localhost:7700/snapshotsDumps (on-demand)
Generate a dump:
curl -X POST -H "Authorization: Bearer $MEILI_KEY" \
http://localhost:7700/dumpsExpected output:
{
"taskUid": 42,
"status": "enqueued",
"type": "dumpCreation",
"enqueuedAt": "2026-04-16T10:30:00Z"
}The dump file appears in /var/lib/meilisearch/dumps/ as a .dump file.
Automate off-site backups with cron
Ship dumps to S3-compatible storage nightly:
sudo tee /usr/local/bin/meili-backup.sh > /dev/null <<'EOF' #!/bin/bash set -euo pipefail MEILI_KEY="your-master-key" TIMESTAMP=$(date +%Y%m%d-%H%M%S) BUCKET="s3://your-backup-bucket/meilisearch"Trigger a dump
curl -sS -X POST -H "Authorization: Bearer $MEILI_KEY" \ http://localhost:7700/dumps >/dev/nullWait for dump to complete (simple poll)
sleep 60Upload latest dump
LATEST=$(ls -t /var/lib/meilisearch/dumps/*.dump | head -1) aws s3 cp "$LATEST" "$BUCKET/dump-$TIMESTAMP.dump"Keep only 30 local dumps
ls -t /var/lib/meilisearch/dumps/*.dump | tail -n +31 | xargs -r rm EOF
sudo chmod 700 /usr/local/bin/meili-backup.sh sudo chown root:root /usr/local/bin/meili-backup.sh
Schedule it:
echo "0 3 * root /usr/local/bin/meili-backup.sh" | sudo tee /etc/cron.d/meili-backupRestoring from a dump
Dumps are imported at startup:
sudo systemctl stop meilisearch
sudo -u meilisearch /usr/bin/meilisearch \
--config-file-path /etc/meilisearch.toml \
--import-dump /var/lib/meilisearch/dumps/20260416-030000.dumpOnce the import completes, restart normally:
sudo systemctl start meilisearchUsing the Built-in Search Preview Dashboard
Meilisearch ships a built-in search preview dashboard served at the root URL of the instance. It is a simple HTML page for testing queries against your indexes without writing code.
Visit:
https://search.yourdomain.com/You will be prompted for your API key. Paste your admin key and select an index. As you type in the search box, results update live. This dashboard is purely client-side -- it never stores your key and is safe to use in production.
The dashboard is disabled when the MEILI_NO_ANALYTICS=true flag is set in combination with --no-dashboard, but it is enabled by default and does not expose any data that the corresponding API key could not already access.
Official SDKs
Meilisearch maintains first-party SDKs for every major language. Installing one is usually a better path than hand-rolling HTTP calls.
| Language | Package | Install |
|---|---|---|
| JavaScript/TypeScript | meilisearch | npm install meilisearch |
| Python | meilisearch | pip install meilisearch |
| PHP | meilisearch/meilisearch-php | composer require meilisearch/meilisearch-php |
| Ruby | meilisearch | gem install meilisearch |
| Go | github.com/meilisearch/meilisearch-go | go get github.com/meilisearch/meilisearch-go |
| Rust | meilisearch-sdk | cargo add meilisearch-sdk |
| Java | com.meilisearch.sdk:meilisearch-java | Maven/Gradle |
| .NET | Meilisearch | dotnet add package Meilisearch |
| Swift | meilisearch-swift | Swift Package Manager |
| Dart | meilisearch | flutter pub add meilisearch |
import { Meilisearch } from 'meilisearch';const client = new Meilisearch({ host: 'https://search.yourdomain.com', apiKey: process.env.MEILI_SEARCH_KEY, });
const results = await client.index('movies').search('inception', { filter: 'year > 2000', sort: ['rating:desc'], limit: 10, });
console.log(results.hits);
Frontend libraries like instant-meilisearch bridge Meilisearch with Algolia's React InstantSearch widgets, so you get polished autocomplete, faceted filters, and pagination UI out of the box.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
401 Unauthorized on every request | Missing or wrong Authorization header | Prefix your key with Bearer: -H "Authorization: Bearer $MEILI_KEY". In production mode, every endpoint except /health requires auth. |
| Service fails to start: "db is in an incompatible version" | Upgraded Meilisearch binary but old data dir | Export a dump with the old version, stop Meilisearch, clear /var/lib/meilisearch/data, start new version with --import-dump. |
413 Request Entity Too Large on bulk insert | Nginx client_max_body_size too small | Increase to 100m or higher in the Nginx config, reload Nginx. |
| High RAM usage, OS starts swapping | Index larger than available RAM | Meilisearch memory-maps the index; swap is expected for datasets > RAM. Upgrade to a larger VPS for hot indexes. |
| Search returns empty results after bulk insert | Indexing task still running | curl http://localhost:7700/tasks -- wait for status: succeeded. Large imports can take minutes. |
Connection refused on port 7700 | Meilisearch bound to wrong address or not running | Check http_addr in config, systemctl status meilisearch, and logs via journalctl -u meilisearch. |
Tenant token rejected: invalid token | Wrong parent API key UID, or token expired | Tokens must be signed with an API key that itself grants access to the index and actions requested. Regenerate with the correct apiKeyUid. |
Dashboard at / shows "Cannot connect" | Browser blocking mixed content or wrong key | Ensure HTTPS is working end-to-end and paste an admin-level key. |
Viewing logs
sudo journalctl -u meilisearch -fFor the last 100 lines:
sudo journalctl -u meilisearch -n 100 --no-pagerFAQ
Is Meilisearch free and open-source?
Yes. Meilisearch is licensed under the MIT License and is free to self-host on any infrastructure. Meilisearch Cloud is a paid managed offering, but the engine itself carries no usage fees, no per-request billing, and no document-count limits.
How much RAM does Meilisearch need?
A general rule is that Meilisearch needs roughly 2x the size of your raw dataset in RAM for optimal performance, because the index is memory-mapped and the OS keeps hot pages resident. For up to 1 million documents with modest payloads (a few KB each), 2 GB of RAM is usually enough. For 10 million documents, plan on 8-16 GB. The engine does not crash when the index is larger than RAM -- the OS simply swaps pages in and out -- but latency increases measurably once working set exceeds RAM.
How does Meilisearch compare to Elasticsearch, Typesense, and Algolia?
Meilisearch is optimized for instant, typo-tolerant search on typical product and content datasets. Simplest to deploy (single binary), best developer experience, great defaults.
Typesense is architecturally similar to Meilisearch (single binary, C++ instead of Rust). Very close in performance. Typesense has richer vector search and curation features today; Meilisearch has simpler tenant tokens and a more polished dashboard.
Elasticsearch / OpenSearch are general-purpose distributed search and analytics engines. Use them when you need aggregations over billions of log lines, complex Lucene queries, or cluster-wide sharding. They are overkill for typeahead search and come with significant operational overhead.
Algolia is a hosted-only SaaS with excellent global edge latency. Meilisearch matches or beats Algolia on features for a fraction of the cost once you self-host.
See our comparison guides: How to Install Typesense on Ubuntu, How to Install Elasticsearch on Ubuntu, and How to Install OpenSearch on Ubuntu.
Can I use Meilisearch for a multi-tenant SaaS?
Yes. Meilisearch supports tenant tokens, which are JWT-style API keys scoped to a filter expression. You sign them with a parent API key and embed per-customer filters (customerId = "abc") so that each user can only search their own documents even though everything lives in a single shared index. This is significantly more efficient than creating one index per tenant and handles thousands of tenants effortlessly.
How do I back up a Meilisearch instance?
Meilisearch has two backup mechanisms. Snapshots are fast binary copies of the data directory -- ideal for crash recovery on the same Meilisearch version. Enable them with schedule_snapshot in the config. Dumps are portable JSON exports that can be restored on different Meilisearch versions -- essential for upgrades and cross-environment migrations. Trigger them with POST /dumps. A production setup should use both: scheduled snapshots locally for fast recovery, plus nightly dumps shipped to off-site object storage.
Does Meilisearch support vector/semantic search?
Yes, since version 1.6. You can either embed documents yourself and store the vectors in a _vectors field, or configure an embedders setting that calls OpenAI, HuggingFace, or a local model to generate embeddings automatically. Hybrid search blends keyword scores with vector similarity using a semanticRatio parameter per query, which is useful for RAG pipelines and semantic product discovery.
What happens if the Meilisearch process crashes mid-index?
Meilisearch uses an LMDB-backed transactional store, so crashes do not corrupt existing indexes. The currently-running indexing task is rolled back and re-enqueued, so you can safely restart the service. This is one of the practical reasons snapshots are fast to take -- the on-disk state is always consistent.
Next Steps
Now that Meilisearch is running on your VPS, here are recommended next steps to build on your setup:
- Wire it into your application -- Install the official SDK for your stack and replace your database
LIKEqueries with Meilisearchsearch()calls. Start with the index that has the most user-facing search load.
- Add InstantSearch UI -- The
instant-meilisearchadapter lets you use Algolia's React/Vue/Angular InstantSearch widgets with Meilisearch as the backend. You get polished autocomplete, faceted filters, and paginated results with minimal code.
- Enable hybrid semantic search -- If your users run long, natural-language queries, configure an embedder (OpenAI, HuggingFace, or a self-hosted model like Ollama -- see our Ollama install guide) and enable hybrid search on your most important index.
- Set up monitoring -- Expose Meilisearch metrics with
MEILI_EXPERIMENTAL_ENABLE_METRICS=trueand scrape them with Prometheus. Alert on queue depth and indexing failures.
- Tune ranking rules per index -- Meilisearch's default ranking pipeline is excellent, but every dataset has quirks. Use the search preview dashboard to iterate on ranking rules, synonyms, and typo tolerance until the top results match what you expect.
- Read the official docs -- The Meilisearch documentation has deep guides on every setting, endpoint, and integration pattern covered here.
Skip the manual setup -- deploy on a VPS built for it.>
Our CloudCore Starter plan comes with enough RAM, NVMe storage, and unmetered bandwidth to run Meilisearch comfortably for most production workloads. Spin one up in under 60 seconds and follow this guide end-to-end in 25 minutes.>
- 4 vCPU, 8 GB RAM, 100 GB NVMe
- Unmetered bandwidth
- Full root access
- EUR 7.50/month starting price>
Launch your CloudCore Starter VPS