Introduction
Running Meilisearch in production requires careful attention to deployment, configuration, security, and maintenance. While Meilisearch is designed to be simple to set up, production environments demand a different approach to ensure reliability, performance, and security.
This guide covers the operational aspects of running Meilisearch at scale. We will explore deployment strategies, configuration options, security best practices, monitoring approaches, backup strategies, and performance optimization techniques. By the end, you will be equipped to run Meilisearch confidently in production environments.
Deployment Strategies
Choosing the right deployment strategy depends on your requirements for availability, scale, and operational complexity.
Single Node Deployment
For many applications, a single Meilisearch instance provides sufficient performance. This approach is simple to set up and maintain while offering excellent search speed for most use cases.
docker run -d \
--name meilisearch \
-p 7700:7700 \
-v meili_data:/meili_data \
-e MEILI_MASTER_KEY=your_master_key \
-e MEILI_DB_PATH=/meili_data \
-e MEILI_ENV=production \
getmeilisearch/meilisearch:v1.12
A single node can handle millions of documents and thousands of queries per second. If your requirements exceed these thresholds, consider scaling horizontally.
Container Orchestration
For production deployments, container orchestration platforms provide essential features like automatic restarts, rolling updates, and scaling capabilities.
Docker Compose
For simpler production setups, Docker Compose provides a good balance of features:
version: '3.8'
services:
meilisearch:
image: getmeilisearch/meilisearch:v1.12
ports:
- "7700:7700"
volumes:
- meili_data:/meili_data
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_DB_PATH=/meili_data
- MEILI_ENV=production
- MEILI_LOG_LEVEL=info
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:7700/health"]
interval: 30s
timeout: 10s
retries: 3
Kubernetes Deployment
For larger deployments, Kubernetes provides advanced orchestration capabilities:
apiVersion: apps/v1
kind: Deployment
metadata:
name: meilisearch
spec:
replicas: 1
selector:
matchLabels:
app: meilisearch
template:
metadata:
labels:
app: meilisearch
spec:
containers:
- name: meilisearch
image: getmeilisearch/meilisearch:v1.12
ports:
- containerPort: 7700
env:
- name: MEILI_MASTER_KEY
valueFrom:
secretKeyRef:
name: meilisearch-secrets
key: master-key
- name: MEILI_ENV
value: "production"
volumeMounts:
- name: meili-data
mountPath: /meili_data
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 7700
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 7700
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: meili-data
persistentVolumeClaim:
claimName: meilisearch-pvc
---
apiVersion: v1
kind: Service
metadata:
name: meilisearch
spec:
selector:
app: meilisearch
ports:
- port: 7700
targetPort: 7700
type: ClusterIP
High Availability Setup
For production systems requiring high availability, consider deploying multiple Meilisearch instances behind a load balancer. While Meilisearch does not have built-in clustering, you can achieve high availability through:
- Multiple Meilisearch instances sharing the same data storage
- A load balancer distributing requests
- A replicated database backing store
# docker-compose.yml for HA setup
version: '3.8'
services:
meilisearch-1:
image: getmeilisearch/meilisearch:v1.12
volumes:
- meili_data:/meili_data
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_DB_PATH=/meili_data
- MEILI_ENV=production
depends_on:
- nfs-server
meilisearch-2:
image: getmeilisearch/meilisearch:v1.12
volumes:
- meili_data:/meili_data
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_DB_PATH=/meili_data
- MEILI_ENV=production
depends_on:
- nfs-server
nfs-server:
image: itsthenetwork/nfs-server-alpine:latest
volumes:
- ./nfs:/exports
environment:
- SHARED_DIRECTORY=/exports
load-balancer:
image: nginx:alpine
ports:
- "7700:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- meilisearch-1
- meilisearch-2
Configuration
Meilisearch provides numerous configuration options to optimize performance and behavior.
Environment Variables
Key environment variables for production deployments:
# Required
MEILI_MASTER_KEY=your_secure_master_key
# Paths and storage
MEILI_DB_PATH=/var/lib/meilisearch
MEILI_SNAPSHOT_DIR=/var/lib/meilisearch/snapshots
# HTTP server
MEILI_HOST=0.0.0.0
MEILI_PORT=7700
# Environment
MEILI_ENV=production
MEILI_LOG_LEVEL=info
# Performance
MEILI_MAX_INDEXING_THREADS=4
MEILI_MAX_SEARCH_THREADS=4
# Features
MEILI_EXPERIMENTAL_VECTOR_STORE=true
Configuration File
For complex configurations, use a configuration file:
# config.toml
master-key = "your_secure_master_key"
[server]
host = "0.0.0.0"
port = 7700
[db]
path = "/var/lib/meilisearch"
[logging]
level = "info"
format = "json"
[indexing]
max_indexing_memory = "1GiB"
max_indexing_threads = 4
[experimental]
vector_store = true
SSL/TLS Configuration
In production, always use SSL/TLS to encrypt communications:
# Generate self-signed certificates for testing
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout.key -out.crt \
-subj "/C=US/ST=State/L=City/O=Organization"
# Start Meilisearch with SSL
./meilisearch --ssl-cert-path=./server.crt \
--ssl-key-path=./server.key \
--master-key="your_master_key"
For production, use certificates from a trusted Certificate Authority.
Security
Securing your Meilisearch deployment protects sensitive data and prevents unauthorized access.
API Keys
Meilisearch supports granular API key permissions:
# Create an API key with search-only permission
curl -X POST 'http://localhost:7700/keys' \
-H 'Authorization: Bearer your_master_key' \
-H 'Content-Type: application/json' \
-d '{
"description": "Search-only key for frontend",
"actions": ["search"],
"indexes": ["products", "documents"],
"expiresAt": "2027-01-01T00:00:00Z"
}'
Key actions include:
search- Execute search queriesdocuments.add- Add documentsdocuments.delete- Delete documentsindexes.create- Create new indexessettings.update- Update index settingsstats.all- Access statisticsversion- View version information
Key Expiration
Always set expiration dates for API keys:
curl -X POST 'http://localhost:7700/keys' \
-H 'Authorization: Bearer your_master_key' \
-H 'Content-Type: application/json' \
-d '{
"description": "Temporary development key",
"actions": ["search"],
"indexes": ["*"],
"expiresAt": "2026-04-01T00:00:00Z"
}'
Tenant Tokens
For multi-tenant applications, use tenant tokens to provide per-customer access:
const { MeiliSearch } = require('meilisearch')
// Generate a tenant token (server-side)
const client = new MeiliSearch({
host: 'http://localhost:7700',
apiKey: 'your_master_key'
})
const tenantToken = client.generateTenantToken(
'tenant-id-123',
{
search: ['allowed-index-1', 'allowed-index-2']
},
{ expiresIn: '1h' }
)
// The frontend uses this token
const frontendClient = new Meilisearch({
host: 'http://localhost:7700',
apiKey: tenantToken
})
Network Security
Restrict network access to your Meilisearch instance:
# Using firewall (UFW)
ufw allow 7700/tcp from 10.0.0.0/8
ufw enable
# Using Meilisearch's built-in options
MEILI_TRUSTED_IP_FORWARDING=10.0.0.0/8
HTTPS Enforcement
Always use HTTPS in production. Configure your reverse proxy to enforce SSL:
server {
listen 443 ssl http2;
server_name search.example.com;
ssl_certificate /etc/ssl/certs/search.crt;
ssl_certificate_key /etc/ssl/private/search.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost: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;
}
}
server {
listen 80;
server_name search.example.com;
return 301 https://$server_name$request_uri;
}
Monitoring
Effective monitoring helps you understand system health and identify issues before they impact users.
Health Check
Meilisearch provides a health endpoint:
curl http://localhost:7700/health
Response:
{
"status": "available",
"indexes": 3,
"version": "1.12.0"
}
Statistics Endpoint
Get detailed statistics about your indexes:
curl -X GET 'http://localhost:7700/indexes/books/stats' \
-H 'Authorization: Bearer your_master_key'
Response:
{
"numberOfDocuments": 100000,
"isIndexing": false,
"fieldDistribution": {
"title": 100000,
"author": 100000,
"description": 100000
}
}
Prometheus Metrics
Configure Prometheus to scrape Meilisearch metrics:
# prometheus.yml
scrape_configs:
- job_name: 'meilisearch'
static_configs:
- targets: ['meilisearch:7700']
Add metrics configuration to Meilisearch:
MEILI_EXPERIMENTAL_METRICS_ENABLED=true
Access metrics at /metrics:
curl http://localhost:7700/metrics
Logging
Configure logging for troubleshooting:
# Set log level
MEILI_LOG_LEVEL=debug # debug, info, warn, error
# Log to file
MEILI_LOG_FILE=/var/log/meilisearch.log
Structured Monitoring Stack
For comprehensive monitoring, integrate with established tools:
version: '3.8'
services:
meilisearch:
image: getmeilisearch/meilisearch:v1.12
# ... configuration
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
Backup and Restore
Protecting your data requires regular backups and a tested restore process.
Snapshots
Meilisearch supports creating snapshots:
# Create a snapshot manually
curl -X POST 'http://localhost:7700/snapshots' \
-H 'Authorization: Bearer your_master_key'
Configure automatic snapshots:
MEILI_SNAPSHOT_DIR=/var/lib/meilisearch/snapshots
MEILI_SCHEDULE_SNAPSHOT=true
MEILI_SNAPSHOT_INTERVAL_SEC=3600 # Every hour
Backup Process
For complete backups, create snapshots and verify them:
#!/bin/bash
set -e
MEILI_HOST="http://localhost:7700"
MEILI_KEY="your_master_key"
BACKUP_DIR="/backups/meilisearch"
DATE=$(date +%Y%m%d_%H%M%S)
# Create snapshot
echo "Creating snapshot..."
curl -X POST "${MEILI_HOST}/snapshots" \
-H "Authorization: Bearer ${MEILI_KEY}"
# Wait for snapshot to complete
sleep 10
# Copy snapshot to backup location
SNAPSHOT_PATH=$(curl -s -X GET "${MEILI_HOST}/snapshots" \
-H "Authorization: Bearer ${MEILI_KEY}" | jq -r '.snapshots[0].file')
cp "${MEILI_SNAPSHOT_DIR}/${SNAPSHOT_PATH}" "${BACKUP_DIR}/meilisearch_${DATE}.snap"
# Verify backup
ls -lh "${BACKUP_DIR}/meilisearch_${DATE}.snap"
echo "Backup completed: ${BACKUP_DIR}/meilisearch_${DATE}.snap"
Restore from Snapshot
To restore from a snapshot:
# Stop Meilisearch
docker stop meilisearch
# Restore snapshot directory
docker run -v meili_data:/meili_data \
-v $(pwd)/snapshots:/snapshots:ro \
getmeilisearch/meilisearch:v1.12 \
./meilisearch --import-snapshot /snapshots/your_snapshot.snap
# Restart Meilisearch
docker start meilisearch
Export/Import
For smaller datasets, export documents as JSON:
# Export all documents from an index
curl -X GET 'http://localhost:7700/indexes/books/documents?limit=100000' \
-H 'Authorization: Bearer your_master_key' \
-o backup_documents.json
Performance Optimization
Optimizing Meilisearch ensures fast response times even under heavy load.
Resource Allocation
Allocate appropriate resources based on your workload:
# Recommended for medium workloads
environment:
- MEILI_MAX_INDEXING_THREADS=4
- MEILI_MAX_SEARCH_THREADS=4
- MEILI_MAX_INDEXING_MEMORY=2GiB
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2000m"
Indexing Optimization
Speed up indexing with proper configuration:
# Batch document additions for better performance
# documents in batches of Add 1000 instead of individually
# Configure indexing threads based on CPU cores
MEILI_MAX_INDEXING_THREADS=8 # For 8+ core systems
Search Optimization
Optimize search performance:
# Limit the number of hits returned when not needed
# Use 'limit' parameter in search requests
# Configure searchable attributes to exclude large fields
curl -X PATCH 'http://localhost:7700/indexes/books/settings' \
-H 'Authorization: Bearer your_master_key' \
-H 'Content-Type: application/json' \
-d '{
"searchableAttributes": ["title", "author", "genre"],
"displayedAttributes": ["*"]
}'
Caching
Implement caching at the application or proxy level:
# Nginx caching configuration
proxy_cache_path /tmp/meilisearch_cache levels=1:2
keys_zone=meilisearch_cache:10m
max_size=100m
inactive=60m;
server {
location / {
proxy_pass http://localhost:7700;
proxy_cache meilisearch_cache;
proxy_cache_valid 200 60m;
proxy_cache_key "$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
}
Query Optimization
Structure queries efficiently:
// Bad: Fetching more data than needed
const results = await index.search('query', {
limit: 1000, // Too high
attributesToRetrieve: ['*'] // Retrieve all fields
})
// Good: Fetch only needed data
const results = await index.search('query', {
limit: 20, // Appropriate limit
attributesToRetrieve: ['id', 'title', 'price'], // Only needed fields
attributesToHighlight: ['title'] // Only highlight needed fields
})
Maintenance
Regular maintenance keeps your Meilisearch deployment running smoothly.
Index Maintenance
Monitor and manage index health:
# Check index status
curl -X GET 'http://localhost:7700/indexes' \
-H 'Authorization: Bearer your_master_key'
# Get index information
curl -X GET 'http://localhost:7700/indexes/books' \
-H 'Authorization: Bearer your_master_key'
Version Upgrades
Follow these steps when upgrading Meilisearch:
- Review release notes for breaking changes
- Create a backup of your data
- Test the upgrade in a staging environment
- Upgrade during low-traffic periods
- Monitor for any issues after upgrade
# Backup before upgrade
./meilisearch-backup.sh
# Pull new image
docker pull getmeilisearch/meilisearch:v1.13
# Recreate container with new image
docker-compose up -d meilisearch
Disk Space Management
Monitor disk usage and clean up unnecessary files:
# Check disk usage
df -h /var/lib/meilisearch
# Remove old snapshots (keep recent ones)
find /var/lib/meilisearch/snapshots -name "*.snap" -mtime +7 -delete
# Clear Meilisearch cache
curl -X DELETE 'http://localhost:7700/cache' \
-H 'Authorization: Bearer your_master_key'
Troubleshooting
Common issues and their solutions.
High Memory Usage
If Meilisearch uses excessive memory:
- Reduce indexing thread count
- Limit document batch sizes
- Increase available memory
- Monitor index size
MEILI_MAX_INDEXING_THREADS=2
MEILI_MAX_INDEXING_MEMORY=512MiB
Slow Search Performance
For slow search queries:
- Check that searchable attributes are configured
- Verify filterable and sortable attributes are set
- Ensure proper indexing
- Monitor system resources
# Check current settings
curl -X GET 'http://localhost:7700/indexes/books/settings' \
-H 'Authorization: Bearer your_master_key'
Indexing Stuck
If indexing appears stuck:
# Check indexing status
curl -X GET 'http://localhost:7700/indexes/books' \
-H 'Authorization: Bearer your_master_key'
# Cancel ongoing task if needed
curl -X DELETE 'http://localhost:7700/tasks/task_id' \
-H 'Authorization: Bearer your_master_key'
External Resources
Conclusion
Operating Meilisearch in production requires attention to deployment architecture, security, monitoring, and maintenance. This guide covered the essential operational aspects including deployment strategies, security configuration, monitoring approaches, backup procedures, and performance optimization.
By following these operational best practices, you can ensure your Meilisearch deployment is reliable, secure, and performant. Remember to regularly review and update your operational procedures as your usage grows and as new Meilisearch features become available.
In the next article, we will explore Meilisearch’s internal architecture, understanding how it achieves its remarkable search speed.
Comments