Self-hosted search in 2026: revisit Meilisearch, Typesense and Manticore Search before you add another search box

Picture an electrical and hardware distributor headquartered in Vadodara, with warehouses in Anand, Bharuch, Godhra, Rajkot and Surat (an invented example, not a real client). About 20,000 products, from LED bulbs and ceiling fans to MCBs, copper wire, conduit and pumps. Around four hundred dealers order through a web and Android app, and product search is a PostgreSQL ILIKE '%term%' on the name. Dealers type the way people type on a phone in a shop: “celing fan”, “submersable pump”, “mcb 32a”, or a five-digit code read off a box. Most of those searches return nothing, and the order moves to WhatsApp.

The product owner wants search-as-you-type with typo tolerance, filters with counts for brand, category, price and stock, “nearest warehouse” sorting, and one rule that cannot break: each dealer sees only the products in their own agreement. The team is two backend developers and one person who also looks after the servers. Elasticsearch and OpenSearch were ruled out as too much engine for 20,000 documents and that team (the fork itself is covered in the Elasticsearch and OpenSearch post). Three proposals arrive. The frontend developer wants Meilisearch. A backend developer who used it at a previous job wants Typesense. The person who ran Sphinx years ago wants Manticore Search, because it speaks SQL.

This post compares those three as they stand on 19 October 2026: licence history, governance, architecture, matching and counting behaviour, facets and filters, multi-tenant keys, operations, security and maintainer health. Managed services and dedicated vector databases are out of scope. The question is what each engine does with the same messy query, and what it takes to keep it running.

Facts come from GitHub releases and LICENSE history, official docs and changelogs, CVE records, GitHub advisories and OSV, and a drill that loaded one invented catalogue into Meilisearch 1.55.0, Typesense 30.2 and Manticore Search 29.9.0 on one shared box. It is not a speed benchmark, and nothing here is legal advice.

The short version

  • Typo tolerance is three different rule sets, and hit counts mean three different things. All three found “celing fan” and “submersable pump”. “led bulp” returned 4,730 hits on Meilisearch and 1,151 on Typesense and on Manticore with fuzzy search, because Meilisearch allows no typo in a four-letter word and by default counts documents matching only some words.
  • Facets and filters agreed exactly when the hit set was the same: category counts, price, boolean, array and geo filters. Differences came from matching, not faceting.
  • Meilisearch 1.55.0 (12 October 2026) is MIT for the Community Edition, but since v1.19.0 (August 2025) some features are Enterprise Edition under BUSL 1.1. Replication and sharding are among them, so the free edition has no built-in high availability.
  • Typesense 30.2 (19 April 2026) is GPL-3.0, keeps the whole index in RAM, and has Raft clustering in the open-source server. Its 31.0 candidates reached RC20 on 13 October 2026, but there has been no stable release for six months.
  • Manticore Search 29.9.0 (11 September 2026) is a 2017 fork of Sphinx, GPLv3-or-later since 6.3.0 (May 2024), with SQL, Galera replication and, since 27.0, opt-in authentication. Permissions are per table, not per row, and its fuzzy search gave the most false positives.
  • Security: published CVEs exist for Typesense (two, fixed in 29.1 and 30.2) and Manticore (one, fixed in 28.4.4). Meilisearch has fixed several issues in 2026 release notes, including two it names as CVEs that the CVE list did not yet contain on 19 October.

Where things stand on 19 October 2026

Dates are GitHub release published_at converted from UTC to IST (UTC+5:30); the Typesense release candidate date is the Docker Hub tag’s last_updated. Licences are from the LICENSE files in each repository.

Project

Release

Date (IST)

Notes

Licence

Meilisearch (meilisearch/meilisearch)

v1.55.0

12 October 2026, 2:51 PM

Latest; inline dynamic search rules (EE only)

MIT (CE); BUSL 1.1 for EE parts

Meilisearch

v1.54.3, v1.53.3, v1.52.4

1 October 2026, 3:24 PM to 3:48 PM

Stability fix backported to three minor lines

Same

Typesense (typesense/typesense)

v30.2

19 April 2026, 9:30 PM

Latest stable; fixes CVE-2026-47216 and CVE-2026-47225

GPL-3.0

Typesense

v29.1

19 April 2026, 9:29 PM

Same two fixes for the 29 line

GPL-3.0

Typesense

31.0.rc20

13 October 2026, 4:34 PM

Docker image only; not a GitHub release

GPL-3.0

Manticore Search (manticoresoftware/manticoresearch)

29.9.0

11 September 2026, 7:50 PM

Latest; bundles Buddy 4.4.3, MCL 14.2.1, backup 1.11.0

GPLv3-or-later

Manticore Search

28.4.4

10 July 2026, 8:11 PM

First release with the CVE-2026-92796 fix

GPLv3-or-later

Manticore Columnar Library

14.2.1

Bundled with 29.9.0

Columnar storage, secondary indexes, KNN

Apache 2.0

GitHub stars on 19 October 2026: Meilisearch about 59,596, Typesense about 27,002, Manticore about 12,060. Open issues: 322, 911 and 651. Stars measure attention, not fitness for your catalogue.

Timeline

Date (IST)

Event

6 July 2017

Manticore Search 2.3.3, the first entry in its changelog, after forking Sphinx 2.3.2

29 January 2018

GPL v2 licence file added to the Typesense repository

12 November 2019

Meilisearch drops the Commons Clause and becomes plain MIT

30 March 2020

Typesense licence text updated to GPL v3

6 February 2023

Meilisearch v1.0.0

2 April 2024

Typesense drops 0.x numbering: 0.25 is followed by 26.0

23 May 2024

Manticore 6.3.0 changes the licence from GPLv2-or-later to GPLv3-or-later

30 January 2025

Manticore 7.0.0; from here each breaking change bumps the major number

25 August 2025

Meilisearch v1.19.0: sharding as the first Enterprise Edition feature under BUSL 1.1

2 March 2026

Meilisearch v1.37.0: replicated sharding, Enterprise Edition only

19 April 2026

Typesense 30.2 and 29.1

19 June 2026

Manticore 27.1.5 round-up: authentication and authorisation (from 27.0.0), sharded tables

11 September 2026

Manticore 29.9.0

17 September 2026

CVE-2026-92796 (Manticore) published

12 October 2026

Meilisearch v1.55.0

First question: what should the search box promise?

“We need typo-tolerant search” is a wish, not a specification. Before comparing engines, write the promise in one sentence and get the product owner to sign it:

For [these query types: product names, codes, brands, partial words], a dealer should find [the right product in the top N] even with [one or two typos, missing letters, wrong spacing], must never see [products outside their agreement], and the filter counts must [match the results shown]. We can rebuild the index from [source of truth] in [minutes] and keep search up through [one node failure, or not].

Then separate three layers, because the engines differ at each one:

  1. Matching rules. Which words may have typos and how many, whether the last word is a prefix, whether all words must match, and how codes are tokenised.
  2. Counting rules. What “number of results” means. Counting documents that match half the query is a different promise from counting full matches.
  3. Operating rules. RAM or disk, restart, backup and restore, upgrades, and who can query what.

What each engine actually is

Meilisearch 1.55.0

Meilisearch started in 2018 as MeiliDB, written in Rust by Meili SAS. Its LICENSE in October 2019 was MIT plus the Commons Clause, which withholds the right to sell the software; a commit on 12 November 2019 made it plain MIT. Version 1.0 came in February 2023. In 2026 it has shipped 52 releases, 24 of them new minor versions, about one every two weeks.

The licence changed again in 2025. The root LICENSE now says parts of the work are the Meilisearch Enterprise Edition (EE) under the Business Source License 1.1 and the rest is MIT (MIT AND BUSL-1.1). The adapted BUSL allows EE code for non-production use only and converts to MIT four years after each version is published. The steps:

  • v1.19.0 (August 2025): sharding, the first EE feature.
  • v1.28.0 (December 2025): separate binaries. The default binary stays MIT; files with “enterprise” in the name are EE.
  • v1.31.0 (December 2025): S3-streaming snapshots move from Community to Enterprise, a breaking change; on-disk snapshots stay in Community.
  • v1.37.0 (March 2026): replicated sharding, also EE.

The docs are not fully in step (the editions page names only sharding; the README also lists S3-streaming snapshots and search rule previews), so read the release notes for your version.

The architecture is simple: one binary, storage in LMDB (a memory-mapped key-value store), and an asynchronous task queue that returns a task id for every write. Documents have no fixed schema; filterable and sortable attributes are index settings. Typo tolerance is on by default: none for words up to four characters, one from five, two from nine, and numbers too unless you set disableOnNumbers. The default matchingStrategy is last: documents matching all words come first, then words are dropped from the end of the query to find more. Hybrid search, geo search, facets and tenant tokens (signed JWTs that carry filters) are in the Community Edition.

Two defaults to know: the default environment is development, which runs without a master key, and telemetry is on unless you pass --no-analytics. In production it refused to start without a master key of at least 16 bytes.

Typesense 30.2

Typesense is written in C++ and calls itself an open-source alternative to Algolia and an easier alternative to Elasticsearch. The repository dates from January 2017; a GPL v2 licence went in on 29 January 2018 and became GPL v3 on 30 March 2020. The README explains why GPL and not AGPL: the server runs as a separate process, and AGPL would make network access a trigger for sharing modifications.

The design choice that matters most is memory. Typesense keeps the entire search index in RAM and the raw documents on disk in RocksDB; its sizing guide says two to three times the size of the searchable fields. On restart it rebuilds the index from disk, so restart time grows with data. High availability is in the open-source server: Raft, at least three nodes to survive one failure, writes forwarded to the leader.

Matching is set per query. Defaults include num_typos 2, min_len_1typo 4, min_len_2typo 7, prefix on the last word, and two thresholds that surprise people: typo_tokens_threshold 1 (look for typo corrections only if fewer than one result was found) and drop_tokens_threshold 1 (drop words only if nothing matched). Collections have a declared schema, which also holds tokenisation options such as token_separators. Scoped search keys embed parameters such as filter_by, signed with HMAC, that the user cannot override. Vector and hybrid search, JOINs, synonyms and curation are all in the open-source server.

Releases are few and large. In April 2024 the project dropped 0.x numbering (0.25.2 was followed by 26.0); nine stable releases have followed, the latest on 19 April 2026. The 31.0 line has been in release candidates on Docker Hub since at least August 2026, with RC20 on 13 October, and main had commits that week. The server configuration reference documents no telemetry setting, and the default --api-address is 0.0.0.0.

Manticore Search 29.9.0

Manticore’s README says it was forked from Sphinx 2.3.2 in 2017; the binary still prints Sphinx copyright lines from 2001 to 2016. The licence was GPLv2-or-later until 6.3.0 (23 May 2024) made it GPLv3-or-later. The bundled Manticore Columnar Library is Apache 2.0, and Manticore Buddy, the PHP sidecar behind fuzzy search, autocomplete, backups and sharding commands, is GPL-3.0.

Version numbers need a note. 29.9.0 is only twenty months after 7.0.0 (January 2025): the release notes tie each new major number (18.0.0, 19.0.0, 21.0.0 and so on) to a breaking change. The 25.0.0 notes list seven since 18.0.0, including two index format bumps, and older versions cannot open indexes written in format 69, so downgrades need planning. Since 25.0.0 the manticore package bundles Buddy, MCL, backup and Galera.

It is the most database-like of the three: SQL over the MySQL protocol, a JSON HTTP API and Elasticsearch-compatible writes. Real-time tables keep a RAM chunk, disk chunks and a binlog. Replication uses Galera, described as virtually synchronous multi-master; native sharded tables came in 26.1.0. Authentication arrived in 27.0.0: off by default, enabled with auth = 1, with grants for read, write, schema, backup, replication and admin on tables or wildcards. There is no row-level rule.

Matching follows its Sphinx roots. Without operators, SQL MATCH() requires all words while JSON match defaults to OR, as the manual notes. Typo tolerance is off by default: fuzzy search is an option (OPTION fuzzy=1) handled by Buddy, needs min_infix_len on the table, and allows two typos per word by default. Telemetry is on unless you set telemetry = 0. The README’s speed claims against Elasticsearch and MySQL are the vendor’s own runs, and I have not used them.

Comparison tables

Cells without a primary source say “Not documented”.

Licence, governance and maintainer health

Meilisearch

Typesense

Manticore Search

Licence

MIT (CE); BUSL 1.1 for EE parts, MIT after four years per version

GPL-3.0 (GPL v2 from 2018 to 2020)

GPLv3-or-later (GPLv2-or-later before 6.3.0); MCL Apache 2.0

Licence changes

Commons Clause removed 2019; EE split from 2025

v2 to v3 in 2020

v2 to v3 in 2024

Steward

Meili SAS

The Typesense company

Manticore Software LTD

Commercial offer

Meilisearch Cloud; EE licence

Typesense Cloud

Support and consulting

Releases in 2026

52 (24 minor)

30.0, 30.1, 30.2, 29.1; 31.0 RCs

Seven GitHub round-ups, 17.5.1 to 29.9.0

Foundation

None

None

None

Architecture

Meilisearch

Typesense

Manticore Search

Language

Rust

C++

C++ with a PHP sidecar (Buddy)

Index storage

LMDB, memory-mapped on disk

Whole index in RAM; raw data in RocksDB

RT tables: RAM chunk, disk chunks, binlog; row-wise or columnar

Schema

Schemaless documents; per-index settings

Declared collection schema

Declared table schema (SQL)

Writes

Asynchronous task queue

Synchronous import API

Synchronous SQL, JSON or bulk

Interfaces

REST

REST

SQL (MySQL protocol), JSON HTTP, Elasticsearch-style writes

Search features

Meilisearch 1.55

Typesense 30.2

Manticore 29.9

Typo tolerance default

On: 0 typos up to 4 letters, 1 from 5, 2 from 9; numbers too

On: up to 2; 1 from 4 letters, 2 from 7; only if fewer than 1 result

Off; OPTION fuzzy=1, fuzziness 2 by default

Prefix (search-as-you-type)

Last word, by default

Last word, by default

word* wildcard or CALL AUTOCOMPLETE

Multi-word default

last: drop words from the end, count partial matches

All words; drop words only if nothing matched

SQL: all words; JSON match: any word

Facets

facets with counts

facet_by; sampling off by default

FACET or GROUP BY

Filters

SQL-like filter expressions

filter_by expressions

SQL WHERE

Geo

_geoRadius, _geoBoundingBox, geo sort

geopoint field, radius and polygon

GEODIST() and polygon functions

Vector and hybrid

Embedders, hybrid.semanticRatio

Auto-embedding, hybrid search

KNN, auto-embeddings, hybrid search

Multi-tenant search

Tenant tokens with embedded filters

Scoped search keys with embedded parameters

Table-level grants; no row filter

Operations

Meilisearch

Typesense

Manticore Search

High availability

Replication and sharding in EE only (v1.37+)

Raft cluster, three or more nodes

Galera replication; sharded tables

Backups

Snapshots (on disk in CE; S3 streaming in EE) and dumps

POST /operations/snapshot, restored as a data directory

manticore-backup, SQL BACKUP, mysqldump

Upgrades

Snapshot first, then --upgrade-db (since v1.51); not atomic; dumps as fallback, never to an older version

Rolling: followers first, leader last; index rebuilt from disk

Read breaking changes; new index formats cannot be opened by older versions

Restart cost

Memory-mapped; fast in the drill

Rebuilds RAM index; grows with data

Fast in the drill; binlog replay

Telemetry default

On (--no-analytics)

Not documented

On (telemetry = 0)

Security

Meilisearch

Typesense

Manticore Search

Authentication default

None in development; master key required in production

API key required at start

Off until auth = 1

Key model

Master key, scoped API keys, tenant tokens

Admin key, scoped keys with actions and collections, scoped search keys

Users, passwords, bearer tokens, grants per table

Default bind address

localhost:7700

0.0.0.0

127.0.0.1 in the package config

TLS

Built-in options

Certificate and key options

HTTPS listener; needs SSL build for auth

Outbound request controls

Non-global IPs blocked since v1.34.1

--proxy-disallowed-dest-cidrs

Not documented

Worked example for the Vadodara scenario

The Vadodara team (invented) re-ran the drill below with their own top 200 failed searches from the PostgreSQL logs.

Step 1. Classify real queries: names with typos, short words (“fan”, “led”), codes, sizes (“1.5 sq mm”, “32a”, “1200mm”) and brands. Each class failed differently in the drill, so each gets its own test.

Step 2. Decide counting before UI. With Meilisearch’s default last strategy, “condiut pipe” reported 1,501 hits because documents with only “conduit” were counted; with matchingStrategy: all it reported 477, like Typesense. Choose what the dealer should see and set it explicitly.

Step 3. Give codes their own rules. Codes like VI-10432 broke each engine differently: Meilisearch matched neighbouring codes through numeric typos, Typesense found nothing for “10432” because the hyphenated code was one token, and Manticore needed fuzzy off to stay exact. The fixes are small:

# Meilisearch: no typos on numbers, all words required for this search
curl -X PATCH "$MEILI/indexes/products/settings/typo-tolerance" \
  -H "Authorization: Bearer $MEILI_ADMIN_KEY" -H 'Content-Type: application/json' \
  -d '{"disableOnNumbers": true}'
# search body: {"q": "mcb 32a", "matchingStrategy": "all", "filter": "in_stock = true"}

# Typesense: split codes on the hyphen at collection creation time
#   {"name": "products", "token_separators": ["-"], "fields": [ ... ]}
# search: q=10432&query_by=sku,name&num_typos=0 for code lookups

# Manticore: fuzzy only for name search, never for codes
#   CREATE TABLE products (...) min_infix_len='2';
#   SELECT * FROM products WHERE MATCH('@sku 10432');
#   SELECT * FROM products WHERE MATCH('@name celing fan') OPTION fuzzy=1;

Step 4. Enforce dealer scope on the server: a Meilisearch tenant token with dealer_ids = 7, or a Typesense scoped key with filter_by: dealer_ids:=7. In both, a client filter for another dealer only narrowed the result. On Manticore the rule must live in the application or in separate tables, because a read grant covers every row.

Step 5. Plan rebuild and failure. PostgreSQL stays the source of truth and the index is a rebuildable copy (20,000 products took under two seconds on each engine in the drill); snapshots only make recovery faster. If semantic search comes later, the trade-offs in the vector search post apply, and all three engines can store vectors next to keywords.

Security and hygiene

On 19 October 2026 the GitHub repository security advisories API returned two published advisories for typesense/typesense and none for meilisearch/meilisearch or manticoresoftware/manticoresearch. CVE records were checked through cveawg.mitre.org and OSV.

  • CVE-2026-47216 (Typesense; published 12 June 2026, 10:42 PM IST; GitHub CNA; CVSS 4.0 score 8.7; GHSA-fpx5-8c99-247j). A crafted request to /multi_search could crash the server without authentication. Affected before 29.1, and 30.0 before 30.2.
  • CVE-2026-47225 (Typesense; same date; CVSS 4.0 score 6.0; GHSA-97x4-gm45-jpcw). With server-side caching and scoped search keys, cached results could be reused across keys with different restrictions. Same fixed versions. The 30.2 notes list the cache-key fix.
  • CVE-2026-92796 (Manticore; published 17 September 2026, 2:02 AM IST; VulnCheck CNA; CVSS 4.0 score 8.7, CVSS 3.1 score 8.8). Permissions were checked only for the first statement in a multi-statement SQL request, so a read-only user could read credential tables and get password hashes usable to log in as an administrator. Affected 27.0.0 to before 28.4.4. The CISA ADP entry records a public proof of concept.
  • Meilisearch published fixes in release notes rather than GitHub advisories: a dump import path traversal (fixed in v1.33.1, January 2026), an SSRF through webhooks, embedders and network settings for keys with write access to configuration (v1.34.1, which now blocks non-global IPs by default), another authenticated SSRF (v1.43.1, May 2026), and on 24 June 2026 v1.47.1 and v1.48.2 for CVE-2026-57824 (index-scoped API keys could reach global state) and CVE-2026-57823 (limited disclosure past tenant token rules). On 19 October 2026 the CVE API returned “record does not exist” for both IDs and OSV had no entry, so the release notes are the only record.

Habits that matter more than CVE counts:

  • Never ship an admin or master key to a browser or app; ship search keys, tenant tokens or scoped keys from your backend, with short expiry.
  • Bind to a private address on purpose. Typesense’s default --api-address is 0.0.0.0.
  • On Manticore, turn on auth = 1 before the port is reachable from anything but the application host, and back up auth.json separately (see the drill).
  • Decide telemetry on purpose: Meilisearch and Manticore send it by default.
  • If untrusted users can configure webhooks, embedders or remote URLs, treat that as a privileged action; several 2026 Meilisearch fixes were in this area.
  • Pin versions, verify checksums, and re-run your tenant tests after every upgrade.

Decision guide

Situation

Lean towards

Why

Small team, one node is acceptable, rebuild from the database in minutes

Meilisearch CE

Simplest operations, strong typo defaults, tenant tokens, MIT

Search must survive a node failure without a commercial licence

Typesense cluster or Manticore with replication

Meilisearch replication is Enterprise Edition only

Catalogue fits comfortably in RAM; you want predictable latency

Typesense

Whole index in memory by design; size RAM with its guide

Team thinks in SQL; you need joins, grouping and log-style queries too

Manticore Search

SQL over the MySQL protocol, columnar storage, Galera

Many tenants share one index and must not see each other

Meilisearch or Typesense

Server-enforced filters in tokens or scoped keys; Manticore grants are per table

Very large data that will not fit in RAM

Meilisearch EE, Manticore, or the Elasticsearch family

Typesense RAM sizing becomes the constraint

Licence must be permissive for redistribution

Meilisearch CE

MIT; the other two are GPL; avoid EE binaries in production without a contract

Vadodara (invented) pick. The team chose Typesense 30.2 as a three-node cluster: the whole catalogue needs well under a gigabyte of RAM, sales staff use search all day so one node failure must not stop orders, and scoped search keys enforce dealer agreements on the server. Codes go into a field with token_separators: ["-"] and are searched with num_typos=0. They pinned 30.2, will test 31.0 when it leaves release candidates, and kept a Meilisearch CE prototype as the fallback if a single node with fast rebuilds turns out to be enough.

Checklist

  1. Write the search promise in one sentence and get it signed.
  2. Export your top failed queries and classify them.
  3. Set matching and counting behaviour explicitly instead of relying on defaults.
  4. Turn off typo tolerance for codes and numbers where a near match is a wrong product.
  5. Enforce tenant scope on the server and test that a client filter cannot widen it.
  6. Check that facet counts match the results the user sees, with and without a query.
  7. Size memory from the engine’s own guide, especially for Typesense.
  8. Practise a restore from snapshot or backup into a fresh directory, including keys and users.
  9. Bind to private addresses, decide telemetry, and keep admin keys off the client.
  10. Pin versions and re-run the whole suite at every upgrade.

Common mistakes

  1. Treating “typo-tolerant” as one feature that every engine implements the same way.
  2. Comparing hit counts across engines without knowing that one counts partial matches.
  3. Letting typo tolerance touch product codes, so “10432” also returns “10433”.
  4. Assuming short words get typo tolerance.
  5. Turning on fuzzy search everywhere without checking false positives such as “led” matching “red”.
  6. Putting an admin key in a mobile app because “it is only search”.
  7. Using a table-level read grant as if it were row-level security.
  8. Choosing Meilisearch for high availability without noticing replication is Enterprise Edition.
  9. Undersizing RAM for Typesense, or forgetting that restart time grows with the index.
  10. Restoring a backup and finding out only then that users and permissions were not in it.

A drill I ran on 19 October 2026

Shared Linux VM (Debian 13, 8 vCPU, 15 GiB RAM, other workloads running), no Docker. Final runs between about 2:29 AM and 2:41 AM IST. One box and one small invented catalogue, so timings show what each step involves, not which engine is faster.

Setup:

  • Meilisearch 1.55.0 Community Edition binary (meilisearch-linux-amd64, SHA-256 matched the GitHub release digest), --env production, a master key, --no-analytics, bound to 127.0.0.1.
  • Typesense 30.2 server tarball from dl.typesense.org (MD5 matched the typesense-server.md5.txt inside it; I found no published SHA-256), bound to 127.0.0.1 with CORS off.
  • Manticore Search 29.9.0 bundle package from Manticore’s APT repository (SHA-256 matched the repository index), unpacked rather than installed, on 127.0.0.1. My first start ran with default telemetry for about four minutes before I set telemetry = 0.
  • Client: Python 3.13.5 standard library over HTTP. The same 20,000 invented products (seven invented brands, eight categories, six warehouses, one to four dealers each) went into all three; the Manticore table had min_infix_len='2'.

Indexing took 1.30 s on Meilisearch (until the task succeeded), 0.59 s on Typesense and 0.77 s on Manticore. Memory after indexing: about 113, 137 and 60 MiB RSS; data on disk 33 MB, 36 MB and 6.1 MB. Single runs on a shared box.

Typo and prefix queries. Manticore was run with and without OPTION fuzzy=1; Meilisearch and Typesense with defaults.

Query

Meilisearch

Typesense

Manticore fuzzy

Manticore plain

ceiling fan

959

959

959

959

celing fan

959

959

959

0

submersable pump

468

468

468

0

mltimeter

156

156

156

0

led bulp

4,730 (all LED items)

1,151

1,151

0

condiut pipe

1,501 (477 with all)

477

477

0

mcb 32a

686 (78 with all)

78

78

78

swich

6,666

6,666

1,887

0

fen

0

0

534 (conduit bends)

0

wier 1.5

0

495

978

0

subm

468

468

2,845

0

10432

16 (exact first, then 10433, 10402)

0

3

1

What the table shows:

  • “swich” gave 6,666 on Meilisearch and Typesense because a typo-corrected prefix matched “switches” and “switchgear” in category names; Manticore matched only “switch”.
  • “fen” and “wier” are short: no typo allowed on Meilisearch, one on Typesense, two on Manticore, whose answer for “fen” was conduit bends.
  • Manticore splits “1.5” into 1 and 5 (CALL KEYWORDS), so 2.5 sq mm wires matched too.
  • With disableOnNumbers: true, Meilisearch returned one hit for “10432”; so did a Typesense collection with token_separators: ["-"].

Relevance. Top results were sensible whenever an engine found anything, but the order differed: on tied scores, Meilisearch and Manticore returned the lowest ids first (8, 31, 72) and Typesense the highest (19990, 19983, 19976), so set an explicit tie-breaker sort. “ceiling fan white 1200” found nothing on Manticore, because 1200 is not the token 1200mm; the other two treated the last word as a prefix. “copper wire 2.5 frls” returned 159 on Manticore without fuzzy and 0 with it, in repeated runs. I did not dig further.

Facets and filters. With the same hit set, all three agreed exactly: in-stock category counts (Lighting 3,731, Switches and sockets 3,040, Switchgear 2,318, Wires and cables 2,281, Conduits and fittings 1,595, Fans 1,585, Tools 749, Pumps 718); fans priced Rs 500 to 3,000 in stock, 629; brand = 'vidyut' in lower case, 2,888, the same as ‘Vidyut’; dealer 7 in an array field, 1,268; within 60 km of Vadodara, 6,728; and category = 'Fan', 0 everywhere, since filters have no typo tolerance. With a query, facets followed matching: “led” gave Lighting 4,730 on two engines, while Manticore fuzzy added 571 wires (it matched “red”).

Tenant scope.

Check

Meilisearch tenant token

Typesense scoped key

Manticore read grant

Rows visible to dealer 7

1,268

1,268

20,000 (no row rule)

Client asks for dealer 8

64 (intersection only)

64 (intersection only)

Not applicable

Read raw documents or list keys

403

401

Users list and writes denied

Tampered token or key

403

401

Wrong password 401

With use_cache=true, alternating scoped keys for dealers 7 and 8 kept returning 1,268 and 1,247 on 30.2, the case behind CVE-2026-47225.

Restart and restore. After a restart, documents were back in 0.12 s on Meilisearch, 3.06 s on Typesense (rebuilding the RAM index) and 0.23 s on Manticore, and all three still refused unauthenticated requests. A Meilisearch snapshot took 1.22 s (11.0 MB file); a second instance started with --import-snapshot in 0.2 s, returned the same top ids and accepted the old search key. A Typesense snapshot returned in 0.02 s; a second node started on a copy of it in 6.43 s with the same results and the two keys that existed at snapshot time. Manticore’s manticore-backup took 0.09 s for the table. The restore was where I learnt the most:

# manticore-backup --restore refused while the daemon ran ("Destination file already exists"),
# then because the config file existed, then because the data dir was missing.
# What worked: stop searchd, move the config away, leave an EMPTY data_dir, then restore.
manticore-backup --config=manticore.conf.keep --backup-dir=/backup --restore=backup-20261018210944
# Restored: 20,000 rows, identical fuzzy results. Not restored: auth.json.
# With auth = 1 and no users, every login failed, including admin, until:
printf 'admin\n%s\n%s\n' "$PW" "$PW" | searchd --config manticore.conf --auth-non-interactive

Neither a table backup nor a full backup contained auth.json, so the dealer user had to be recreated. Practise restores with security in them, not only data.

What this box could not test: clusters and failover, large data or concurrency, Hindi or Gujarati text, vector and hybrid search, upgrades, Meilisearch EE and Typesense 31.0 candidates. All three servers were stopped by 2:41 AM IST. Scripts, logs and results are under drill47/.

Unlearn

  • Unlearn “typo-tolerant” as a checkbox.
  • Unlearn that a result count means the same thing in every engine.
  • Unlearn that a fuzzier search is a better search.
  • Unlearn that an open-source licence on the repository covers every binary on the release page.
  • Unlearn trusting a restore that brings back data but not users.

Re-learn

  • Re-learn your dealers’ real queries, not the demo queries.
  • Re-learn the three layers: matching rules, counting rules, operating rules.
  • Re-learn tokenisation for codes, sizes and decimals.
  • Re-learn where your index lives: RAM, memory-mapped disk, or chunks and binlogs.
  • Re-learn the licence of each feature you plan to use, release by release.

Closing

Self-hosted search in 2026 is less about raw speed and more about rules you can explain to a user. Meilisearch 1.55 is the easiest to run and the most forgiving with typos, with an MIT core and an Enterprise Edition that now owns replication and sharding. Typesense 30.2 keeps everything in RAM, ships Raft clustering and scoped keys in its GPL server, and is waiting on 31.0. Manticore Search 29.9 brings SQL, Galera and a Sphinx lineage, with opt-in authentication and fuzzy search that needs careful tuning. Learn the three layers. Unlearn “typo-tolerant” as a feature name. Re-learn your own queries and codes. Practise a restore with keys and users in it. Apply it before you add another search box.

Sources

Meilisearch

Typesense

Security records

Internal

comments powered by Disqus

Releted Posts

Log storage in 2026: revisit Grafana Loki, VictoriaLogs and OpenObserve before you keep another month of logs

Picture a platform team in Pune that runs a B2B lending stack for NBFCs across Maharashtra and Gujarat (an invented example, not a real client).

Read more

Schema migrations in 2026: revisit Atlas, Flyway and Liquibase before you ship another ALTER

Picture a retail SaaS company in Coimbatore that runs order management for textile wholesalers across Tamil Nadu (an invented example, not a real client).

Read more

Change data capture in 2026: revisit Debezium, Apache Flink CDC and PeerDB before you stream another table

Picture a SaaS company in Pune that runs billing for FMCG distributors across Maharashtra (an invented example, not a real client).

Read more