Skip to content
STACK IT FAST

Meilisearch

Curated OSSClassicSearch Engine20+ people

Audited from github.com/meilisearch/meilisearch

Meilisearch is a Rust search engine server: an actix-web HTTP API (crates/meilisearch) in front of the milli indexing and ranking engine, which stores each index as its own LMDB environment via heed and supports vector search through arroy, hannoy, and candle embeddings.

Language
Rust
Database
LMDB
Hosting
Docker
Running for
5 years
Team
20+ people

Why this architecture

Keeping the milli search engine as a dependency-free library separate from the actix-web server crate lets ranking and indexing logic be tested and reused independently of HTTP, while per-index LMDB environments make each index independently portable and snapshot-able.

Tech stack by layer

6 technologies · audited Sep 17, 2026
Backend & APIs
  • RustImplements the entire engine across the crates/ Cargo workspace (20+ crates).
  • Actix-webHTTP server framework exposing the REST API in the meilisearch crate.
  • TokioAsync runtime used by the HTTP server and the index scheduler for background tasks.
  • milliStandalone indexing, ranking, tokenization, and filtering engine with no HTTP dependency.
  • index-schedulerOwns the task queue and background indexing jobs, decoupled from request handling.
  • meilisearch-authIssues and validates HMAC-signed API keys with scoped permissions.
Data & Persistence
  • LMDBEach search index is a separate memory-mapped LMDB environment via the heed binding.
  • S3Optional snapshot and backup target for the index scheduler via the rusty-s3 client.
  • Vector search (arroy/hannoy)Approximate nearest-neighbor index used for semantic and hybrid search over embeddings.
Infrastructure & Deploy
  • DockerMulti-stage Rust build produces a minimal Alpine-based runtime image.
  • PrometheusExposes process and server metrics; a sample scrape config ships in assets/.
  • GrafanaA ready-made dashboard for visualizing the exposed Prometheus metrics.
Tooling, Testing & Ops
  • GitHub ActionsRuns the test suite, fuzzers, benchmarks, and publishes Docker/apt/brew releases.
  • xtaskIn-repo cargo xtask crate drives benchmark workloads and release automation.
  • fuzzersDedicated fuzzing crate targets the indexing and filter-parsing code paths.

Meilisearch architecture diagram

Open SVG
Meilisearch architecture diagramClients → meilisearch (search · documents); meilisearch → index-scheduler (enqueue tasks); index-scheduler → milli (index); meilisearch → milli (search); milli → Indexes (heed); milli → Vector index (ANN); index-scheduler → S3 (snapshots); milli → Embedders (embed)CLIENTSSERVICESWORKERS & JOBSDATA & STORAGEEXTERNALClientsREST · SDKsmeilisearchActix-web · auth keysindex-schedulertask queuemilliindexing · rankingIndexesLMDB per indexVector indexarroy / hannoyS3snapshots (optional)Embeddersremote embeddingsindexsearch · documentsenqueue taskssearchheedANNsnapshotsembed
How the main components of Meilisearch connect, drawn from the audited repository.
Diagram as text
  • Clients (REST · SDKs) → meilisearch (Actix-web · auth keys): search · documents
  • meilisearch (Actix-web · auth keys) → index-scheduler (task queue): enqueue tasks
  • index-scheduler (task queue) → milli (indexing · ranking): index
  • meilisearch (Actix-web · auth keys) → milli (indexing · ranking): search
  • milli (indexing · ranking) → Indexes (LMDB per index): heed
  • milli (indexing · ranking) → Vector index (arroy / hannoy): ANN
  • index-scheduler (task queue) → S3 (snapshots (optional)): snapshots
  • milli (indexing · ranking) → Embedders (remote embeddings): embed

Key architectural decisions

6 decisions
  1. 01

    Search engine and HTTP server are separate crates

    crates/milli implements indexing, ranking, filtering, and tokenization as a standalone library with no actix-web dependency, while crates/meilisearch wraps it in an HTTP server, so the engine itself could be embedded or tested without a server process.

  2. 02

    Each index is its own LMDB environment, not a shared database

    crates/milli/Cargo.toml depends on heed (an LMDB binding) with serde-json and serde-bincode features. Every index gets its own memory-mapped LMDB store, so individual indexes can be moved, backed up, or snapshotted independently of the rest of the instance.

  3. 03

    Task scheduling is a dedicated crate, decoupled from request handling

    crates/index-scheduler/Cargo.toml is separate from crates/meilisearch and owns the task queue, background indexing jobs, and optional S3 snapshotting via rusty-s3, so slow indexing work does not block the request-handling code path.

  4. 04

    Vector search combines a local ANN index with optional remote embeddings

    crates/milli/Cargo.toml depends on arroy and hannoy for approximate nearest-neighbor search plus candle-core, candle-transformers, tokenizers, and hf-hub for local embedding models, while external-crates/async-openai lets the same pipeline call remote providers such as OpenAI.

  5. 05

    Open-core licensing keeps Community and Enterprise Editions in one repo

    The repository ships three license files (LICENSE, LICENSE-MIT, LICENSE-EE), and crates such as meilisearch-types and index-scheduler gate code behind an "enterprise" Cargo feature flag, so Community Edition and Enterprise Edition sources live side by side instead of in separate repositories.

  6. 06

    The HTTP API is generated from code with utoipa, not hand-written

    crates/meilisearch and crates/meilisearch-types depend on utoipa (with actix_extras and openapi_extensions features), and a dedicated crates/openapi-generator crate produces the OpenAPI spec from route and type definitions, checked in CI by check-openapi-file.yml.

How Meilisearch is built

How Meilisearch is structured

Meilisearch is a Cargo workspace (Cargo.toml) of more than twenty crates under crates/ plus two vendored external-crates/. The HTTP-facing crate, crates/meilisearch, depends on crates/index-scheduler for task management, crates/meilisearch-auth for API keys, crates/meilisearch-types for shared request/response types, and (transitively through those) crates/milli, the actual search engine. Supporting crates handle narrower concerns: crates/filter-parser implements the filter expression grammar with nom, crates/dump handles export/import snapshots, crates/file-store manages uploaded document files, crates/routes and crates/routes-macros generate route registration boilerplate, and crates/meilitool is a separate CLI for offline database maintenance. crates/openapi-generator produces the public OpenAPI specification from the same route and type definitions the server uses. Benchmark workload definitions live in workloads/ (JSON files like hackernews.json, movies.json) and are driven by the crates/xtask dev-tooling crate.

Backend & APIs

crates/meilisearch/Cargo.toml depends on actix-web (with compress-brotli, compress-gzip, and rustls-0_23 features) for the HTTP server, tokio (full feature set) as the async runtime, and deserr for deserializing and validating request bodies directly into typed structs. Authentication and authorization run through crates/meilisearch-auth, which depends on hmac, sha2, and jsonwebtoken (via the meilisearch crate) to issue and check scoped, HMAC-signed API keys rather than delegating to an external auth provider. crates/meilisearch-types centralizes the request/response and settings types shared by the server and the OpenAPI generator, and depends on utoipa (with actix_extras, preserve_order, and openapi_extensions features) so the API schema is derived from those same Rust types instead of maintained by hand — CI enforces this with check-openapi-file.yml and db-change-missing.yml/db-change-comments.yml workflows that flag undocumented storage-format changes.

Data & persistence

The core storage abstraction lives in crates/milli, which depends on heed (an LMDB Rust binding, with serde-json and serde-bincode features): each index is its own LMDB environment on disk, memory-mapped for reads, which is why Meilisearch indexes can be individually copied, moved, or restored. crates/index-scheduler owns everything above that per-index storage: it queues indexing and settings-update tasks, tracks their state, and — via the rusty-s3 dependency — can push and pull snapshots to and from S3-compatible object storage for backup and restore. For vector and hybrid search, crates/milli depends on arroy and hannoy for approximate nearest-neighbor indexing over embedding vectors, and on candle-core, candle-transformers, tokenizers, and hf-hub to run small embedding models locally without a network call; external-crates/async-openai, vendored in the workspace, lets the same embedder pipeline call a remote provider such as OpenAI instead. crates/dump handles full-instance export/import in a versioned dump format independent of the live LMDB layout, used for major-version upgrades.

Build, test & deploy

The release build path is the Dockerfile: a rust:1.89-alpine3.22 builder stage compiles meilisearch and meilitool with cargo build --release, and the resulting binaries are copied into a minimal alpine:3.22 runtime image started under tini. .github/workflows/publish-docker-images.yml publishes that image, while publish-apt-brew-pkg.yml and publish-release-assets.yml build and distribute native apt/brew packages and platform binaries directly from the same source. Correctness and performance are both covered in CI: test-suite.yml and flaky-tests.yml run the Rust test suite (many crates pin insta = "=1.39.0" for snapshot testing), fuzzer-indexing.yml runs the crates/fuzzers fuzz targets against the indexing pipeline, and bench-pr.yml/bench-push-indexing.yml/bench-manual.yml run the workloads/*.json benchmark suite through crates/xtask to catch performance regressions. sdks-tests.yml runs the official client SDK test suites against a built server to catch API breakage before release.

Self-hosting notes

Self-hosting requires only the compiled meilisearch binary (from source via cargo build --release, the published Docker image, or an apt/brew package) and a writable data directory for its LMDB-backed indexes — there is no separate database server to provision. assets/prometheus-basic-scraper.yml and assets/grafana-dashboard.json show the expected monitoring setup: Meilisearch exposes Prometheus-format metrics (the prometheus crate dependency with the process feature) that a scrape config can pull and a matching Grafana dashboard can visualize. Snapshot-based backup and restore, including to S3-compatible storage via crates/index-scheduler's rusty-s3 dependency, is the documented path for disaster recovery rather than direct LMDB file copying while the server is running. Enterprise Edition features, gated by an enterprise Cargo feature flag across several crates, require a license and are not enabled in a default Community Edition build.

What to copy (and what not to)

Separating the storage/ranking engine (crates/milli) from the HTTP layer (crates/meilisearch) so the engine has zero web-framework dependencies is a strong pattern worth copying in any server that might need to be embedded, tested headlessly, or reused in a different transport later. Using one memory-mapped LMDB environment per logical unit of data (per index here) rather than one shared database file is a good default for workloads that need independent backup, migration, or deletion of individual data sets, though it adds file-handle and memory-mapping overhead that a single shared store would avoid at very large index counts. Generating the OpenAPI spec from the same Rust types used at runtime (via utoipa) and enforcing that in CI is worth adopting broadly, since it removes an entire class of documentation-drift bugs that hand-maintained OpenAPI files are prone to.

Sources & repo audit

Audited
Sep 17, 2026
Commit
1380ada
License
NOASSERTION

Independent analysis of repository at github.com/meilisearch/meilisearch. Spotted an inaccuracy? Use the claim form to request a correction.

Show this stack on your README or website
Tech stack of Meilisearch
[![Tech stack of Meilisearch on STACK IT FAST](https://stackitfast.com/badge/meilisearch.svg)](https://stackitfast.com/project/meilisearch)

Paste it into your README. It shows your current stack and links to this page.

Use this stack

Scaffold it with your agent

Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Meilisearch's architecture.

  1. 1Copy the promptThe full markdown spec, with every layer and decision.
  2. 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
  3. 3Paste and scaffoldUse it as the first instruction; review before you ship.
use-this-stack.md · 60 lines · 7.6 KB
# MISSION: Scaffold "Meilisearch" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Meilisearch**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Meilisearch
- **What It Does**: Meilisearch is a Rust search engine server: an actix-web HTTP API (crates/meilisearch) in front of the milli indexing and ranking engine, which stores each index as its own LMDB environment via heed and supports vector search through arroy, hannoy, and candle embeddings.
- **Domain & Category**: Search Engine
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Keeping the milli search engine as a dependency-free library separate from the actix-web server crate lets ranking and indexing logic be tested and reused independently of HTTP, while per-index LMDB environments make each index independently portable and snapshot-able.
- **Live Website Reference**: https://meilisearch.com
- **Source Repository**: https://github.com/meilisearch/meilisearch
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Rust, Actix-web, LMDB, Tokio, Docker, Prometheus
- **Primary Language(s)**: Rust
- **License of the reference repo**: NOASSERTION
- **Backend & APIs**: Rust — Implements the entire engine across the crates/ Cargo workspace (20+ crates).; Actix-web — HTTP server framework exposing the REST API in the meilisearch crate.; Tokio — Async runtime used by the HTTP server and the index scheduler for background tasks.; milli — Standalone indexing, ranking, tokenization, and filtering engine with no HTTP dependency.; index-scheduler — Owns the task queue and background indexing jobs, decoupled from request handling.; meilisearch-auth — Issues and validates HMAC-signed API keys with scoped permissions.
- **Data & persistence**: LMDB — Each search index is a separate memory-mapped LMDB environment via the heed binding.; S3 — Optional snapshot and backup target for the index scheduler via the rusty-s3 client.; Vector search (arroy/hannoy) — Approximate nearest-neighbor index used for semantic and hybrid search over embeddings.
- **Infrastructure & deploy**: Docker — Multi-stage Rust build produces a minimal Alpine-based runtime image.; Prometheus — Exposes process and server metrics; a sample scrape config ships in assets/.; Grafana — A ready-made dashboard for visualizing the exposed Prometheus metrics.
- **Tooling, testing & ops**: GitHub Actions — Runs the test suite, fuzzers, benchmarks, and publishes Docker/apt/brew releases.; xtask — In-repo cargo xtask crate drives benchmark workloads and release automation.; fuzzers — Dedicated fuzzing crate targets the indexing and filter-parsing code paths.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/meilisearch/meilisearch @ 1380ada)
1. **Search engine and HTTP server are separate crates**: crates/milli implements indexing, ranking, filtering, and tokenization as a standalone library with no actix-web dependency, while crates/meilisearch wraps it in an HTTP server, so the engine itself could be embedded or tested without a server process.
2. **Each index is its own LMDB environment, not a shared database**: crates/milli/Cargo.toml depends on heed (an LMDB binding) with serde-json and serde-bincode features. Every index gets its own memory-mapped LMDB store, so individual indexes can be moved, backed up, or snapshotted independently of the rest of the instance.
3. **Task scheduling is a dedicated crate, decoupled from request handling**: crates/index-scheduler/Cargo.toml is separate from crates/meilisearch and owns the task queue, background indexing jobs, and optional S3 snapshotting via rusty-s3, so slow indexing work does not block the request-handling code path.
4. **Vector search combines a local ANN index with optional remote embeddings**: crates/milli/Cargo.toml depends on arroy and hannoy for approximate nearest-neighbor search plus candle-core, candle-transformers, tokenizers, and hf-hub for local embedding models, while external-crates/async-openai lets the same pipeline call remote providers such as OpenAI.
5. **Open-core licensing keeps Community and Enterprise Editions in one repo**: The repository ships three license files (LICENSE, LICENSE-MIT, LICENSE-EE), and crates such as meilisearch-types and index-scheduler gate code behind an "enterprise" Cargo feature flag, so Community Edition and Enterprise Edition sources live side by side instead of in separate repositories.
6. **The HTTP API is generated from code with utoipa, not hand-written**: crates/meilisearch and crates/meilisearch-types depend on utoipa (with actix_extras and openapi_extensions features), and a dedicated crates/openapi-generator crate produces the OpenAPI spec from route and type definitions, checked in CI by check-openapi-file.yml.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
   - Structure as a Turborepo monorepo with strict package boundaries:
     - `apps/web`: Application UI, routing, layouts, and server endpoints.
     - `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
     - `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
     - `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
   - Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
   - Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
   - Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
4. **Design System & Aesthetics**:
   - Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
   - Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
   - Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
   - Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (LMDB, S3, Vector search (arroy/hannoy)): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.
Scaffolded something with this prompt?
Would you pick this stack for a search engine project?

Frequently asked about Meilisearch

What is Meilisearch built with?

Meilisearch is written in Rust: an actix-web HTTP server (crates/meilisearch) sits in front of the milli indexing and ranking engine (crates/milli), which stores each index as its own LMDB environment via the heed crate, all on the Tokio async runtime.

Does Meilisearch need a backend?

No, Meilisearch is the backend. It runs as a standalone search server; applications talk to it through its REST API or one of the official client SDKs rather than through an application server in this repository.

Can I self-host Meilisearch?

Yes. The Dockerfile builds a minimal Alpine-based image from source, and publish-apt-brew-pkg.yml and publish-release-assets.yml distribute native binaries and apt/brew packages, so it can run as a container or a standalone process.

Does Meilisearch support vector or semantic search?

Yes. crates/milli depends on arroy and hannoy for approximate nearest-neighbor vector indexes, candle-core, candle-transformers, and hf-hub for running local embedding models, and external-crates/async-openai for calling remote embedding providers such as OpenAI.

How is Meilisearch licensed?

It uses an open-core model: the workspace Cargo.toml declares an MIT license for the Community Edition core, while LICENSE-EE and "enterprise" Cargo feature flags in crates like meilisearch-types and index-scheduler cover Enterprise Edition-only functionality.

One email a month: new deep dives and stack trends

New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.

use-this-stack.md