Meilisearch is a search-as-you-type engine that's genuinely easy to run. It handles typo tolerance, ranking, faceting, filters and synonyms out of the box, has a drop-in JavaScript SDK, and returns results in a few milliseconds on a few hundred thousand documents.
What it is
Drop a JSON document into an index and it becomes searchable within a second. It's opinionated in the good way: the ranking rules work sensibly out of the box, so you get usable search without a relevance-tuning project. Restrict it with a master key for writes and a search-only key for the frontend.
Before you start
- Meilisearch must not be exposed directly to the internet. A search key grants read access to an index, and an open instance is scraped within days. Put it behind a reverse proxy with auth.
- The
masterkey grants full control including reindexing. Generate it explicitly, then never put it in frontend code. - There's no built-in auth. A
search-onlyAPI key is a capability, not a user identity — it's safe to ship in a browser, and anyone who has it can read that index.
1 — Write the compose file
services:
meilisearch:
image: getmeili/meilisearch:v1.12
container_name: meilisearch
restart: unless-stopped
ports:
- "127.0.0.1:7700:7700"
environment:
MEILI_ENV: production
MEILI_MASTER_KEY: CHANGE_ME_master_key_32_chars_min
MEILI_NO_ANALYTICS: "true"
MEILI_DB_PATH: /meili_data
volumes:
- ./data.ms:/meili_data
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost:7700/health"]
interval: 30s
timeout: 5s
retries: 3
ulimits:
nofile:
soft: 65536
hard: 65536
2 — Start it
mkdir -p ~/services/meilisearch
cd ~/services/meilisearch
docker compose up -d
curl -s http://127.0.0.1:7700/health | jq
3 — First-run setup
- Add an index and set its primary key:
curl -X POST http://127.0.0.1:7700/indexes -H "Authorization: Bearer CHANGE_ME_master_key_32_chars_min" -H "Content-Type: application/json" -d '{"uid":"books","primaryKey":"id"}' - Load documents:
curl -X POST http://127.0.0.1:7700/indexes/books/documents -H "Authorization: Bearer CHANGE_ME" --data-binary @books.json - Mark settings as searchable/filterable/sortable. Meilisearch indexes all fields by default, which is rarely what you want once you hit real data — filterable fields in particular are needed before you can filter on them.
- Create a search-only key scoped to that one index with
actions: ["search"]and no indexes restriction beyond it. That key is safe in a browser bundle. - Test typo tolerance by searching a deliberately misspelled word. If it returns nothing, your searchable attributes are wrong, not the engine.
4 — Query it
# the widget UI, for a sanity check
open http://127.0.0.1:7700
# a real query
curl -s -X POST "http://127.0.0.1:7700/indexes/books/search" \
-H "Authorization: Bearer SEARCH_ONLY_KEY" \
-H "Content-Type: application/json" \
-d '{"q":"hikari","limit":5,"attributesToHighlight":["title"]}' | jq
/tasks or watch the task status before assuming a document is searchable. This trips up everyone exactly once.