← All playbooks
Hosted search migration

Algolia → Meilisearch

Browse each Algolia index and add the hits to Meilisearch. Set the primary key yourself. objectID often works, until another field also ends in id, or the id contains a character Meilisearch rejects.

Typical timeline8–20 business days30–70 hours active work
Statusneeds review
Source profileMeilisearch Algolia migration guide reviewed 2026-11-01
Destination profileMeilisearch primary key docs reviewed 2026-11-01
Documentation date
Review window
Evidence5 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

Algolia

Reasons to stay
  • Exceptionally fast hosted search combines polished relevance controls with mature frontend tooling
  • Managed indexing, relevance, filtering, and globally available query APIs reduce search operations
Reasons to leave
  • Record, operation, and feature pricing can rise quickly while ranking configuration remains proprietary
  • Ranking behavior, analyzers, schemas, and learned signals require careful revalidation after migration
New platform

Meilisearch

What gets better
  • Open-source typo-tolerant search with a small API and an optional managed cloud
  • Managed indexing, relevance, filtering, and globally available query APIs reduce search operations
What gets worse
  • Primary keys, ranking rules, and heavy update workloads need explicit setup that a hosted index used to hide
  • Ranking behavior, analyzers, schemas, and learned signals require careful revalidation after migration
Best of the move

Meilisearch: Open-source typo-tolerant search with a small API and an optional managed cloud. This removes a major source-side concern: Record, operation, and feature pricing can rise quickly while ranking configuration remains proprietary.

Worst of the move

What you lose: Exceptionally fast hosted search combines polished relevance controls with mature frontend tooling. What you inherit: Primary keys, ranking rules, and heavy update workloads need explicit setup that a hosted index used to hide.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome12 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 7, Manual rebuild: 3, Not transferred: 2.
Clean0
Partial7
Manual3
Lost2
Mapping route9 of 10 fields have a destination path

This timeline assumes

  • You are moving search indexes, not Algolia Recommend or a personalization campaign.
  • The site already documents Algolia → Typesense Cloud and Algolia → Elastic Cloud.
  • Meilisearch is v1 or newer. The official script expects the v4 Algolia JavaScript client in its Node example.
  • You can read the index with an Algolia admin key and write with a Meilisearch admin key.
  • Algolia stays in place until the same queries have been compared on both engines.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
RecordspartialcriticalMeilisearch's guide browses an index with browseObjects and uploads hits with addDocumentsInBatches in batches of 100,000. That copies JSON. It does not copy index settings unless you set them afterwards.Count hits per index before and after the task succeeds.
Primary keymanualcriticalMeilisearch infers a primary key from the first document by looking for one attribute whose name ends in id. Algolia sends objectID, which matches. If the hit also has categoryID or any second id field, inference fails with index_primary_key_multiple_candidates_found and that batch is not stored.Create the index with primaryKey set to objectID. Do not rely on inference.
Document id characterspartialcriticalA document id must be an integer or a string of letters, digits, hyphens, and underscores. Meilisearch says one bad id fails the whole batch, because addition is atomic.Scan objectIDs. Rewrite illegal characters and keep a map back to the Algolia id.
Primary key lock-inmanualhighMeilisearch says you cannot change the primary key while documents are in the index. You delete the documents, change the key, and add them again.Pick objectID, or a cleaned id, before the first successful add.
Searchable attributes and rankingpartialcriticalMeilisearch maps searchableAttributes directly and turns customRanking into rankingRules. Algolia's ranking tie-break list has no one-to-one copy. Results will not be byte-identical.Set searchableAttributes in the same order you care about. Compare a saved query list before cutover.
Facets and replicaspartialhighattributesForFaceting becomes filterableAttributes. Sort replicas are not separate indexes. You mark sortableAttributes and pass sort at query time.List every replica and the sort it existed to serve. Add those attributes to sortableAttributes.
SynonymspartialmediumMeilisearch's comparison says two-way and one-way synonyms map. Alt corrections and placeholders do not.Export synonyms and rewrite the ones with no equivalent. Symfony added a long synonym list, including yaml/yml, after the documents were in.
Query rules and personalizationlosthighRules that pin, hide, or redirect results, and Algolia personalization, are not in the document upload.Export the rules you still need. Rebuild the few that change revenue queries, or drop them in writing.
AnalyticslostmediumMeilisearch's settings table says Algolia click analytics is a separate Analytics API, not an index setting that copies over.Export the searches you use for zero-result reports before you cancel Algolia.
InstantSearch UIpartialhighMeilisearch says InstantSearch widgets need the Instant Meilisearch adapter. A hand-rolled Algolia client is a rewrite. Settings and search parameters are different objects. You cannot pass an index setting as a query parameter.Swap the client in a branch and run the widget list you actually render.
Geo and snippetspartialmediumaroundLatLng becomes a _geoRadius filter. aroundPrecision has no equivalent. Snippets become attributesToCrop plus cropLength. restrictHighlightAndSnippetArrays is not supported.Rewrite geo queries and check cropped fields on a long document.
Indexing loadmanualhighIn February 2023, schappim wrote on Hacker News that a 50,000-record catalog with constant inventory updates fell hours behind on Meilisearch, and that part of the app moved to Elastic. Meilisearch's reply said indexing had improved. Treat that report as a 2023 workload, then measure yours.Replay a day of updates in staging and watch the task queue.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
IndexMeilisearch indexmanualOne index per Algolia index unless you signed a merge.
HitDocumenttransformbrowseObjects, then addDocuments.
objectIDPrimary keytransformSet primaryKey explicitly. Clean illegal characters.
searchableAttributessearchableAttributestransformOrder matters.
attributesForFacetingfilterableAttributestransformStrip filterOnly and searchable modifiers.
Replica sortsortableAttributes plus a sort parametertransformNo replica index.
customRankingrankingRulestransformdesc(popularity) becomes popularity:desc.
SynonymSynonymtransformTwo-way and one-way map. Placeholders do not.
Query ruleNo destinationunsupportedRebuild or drop.
InstantSearch widgetInstant MeilisearchtransformCheck the adapter's supported widgets.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep a copy of every index's hits and settings before you point the app at Meilisearch.

  1. Export settings, synonyms, and rules from each Algolia index.
  2. Browse hits to a file and record the count.
  3. Save the query list you will use for comparison, including typos.
  4. Note which objectIDs contain characters outside letters, digits, hyphens, and underscores.
  5. Keep the Algolia app running.

Proof to capture: Each index has a hit count, a settings JSON, and a list of ids that need rewriting.

Transformation · Algolia browseObjects and Meilisearch addDocuments

Browse and add

Copy hits without inferring the wrong primary key.

  1. Create the index with primaryKey objectID, or your cleaned id field.
  2. Browse the Algolia index.
  3. Rewrite illegal ids.
  4. Add documents and wait until the task status is succeeded.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · updateSettings and updateSynonyms

Settings translation

Restore the filters and sorts the UI already sends.

  1. Set searchableAttributes, filterableAttributes, and sortableAttributes.
  2. Append custom ranking rules after Meilisearch's defaults.
  3. Import synonyms that have an equivalent.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Pilot

Inference picks the wrong id

criticallikely likelihood

Hits contain objectID and another field ending in id.

Consequence
The task fails and the batch is empty.
Mitigation
Set primaryKey yourself.

Stop if: The first task ends in index_primary_key_multiple_candidates_found.

Pilot

One bad id drops the batch

criticalpossible likelihood

An objectID contains a character Meilisearch rejects.

Consequence
None of the documents in that atomic batch are indexed.
Mitigation
Scan ids before the add.

Stop if: The error code is invalid_document_id.

Cutover

Ranking is treated as identical

highlikely likelihood

The app switches when counts match but the top hits differ.

Consequence
Merchandised queries regress.
Mitigation
Compare a saved query list on both engines.

Stop if: A revenue query's top result changed and nobody signed it.

06Precise timeline

Do the work in this order.

Estimate forA handful of Algolia indexes moving to Meilisearch, self-hosted or Cloud
Total elapsed8–20 business days
Active work30–70 hours
BufferAdd time for query rules, several locales, or a catalog that updates all day.
01
Days 1–3Indexes and id rules2–3 days
02
Days 3–5Export settings and hits1–3 days
03
Days 5–12Stage the index4–8 days
04
Days 12–16Switch the client1–3 days
05
Days 15–22Watch updates4–7 days
  1. Days 1–3 · inventory

    Indexes and id rules

    6–10 hours active2–3 days elapsedSearch owner waiting
    • List indexes, replicas, rules, and synonyms.
    • Scan objectIDs for illegal characters and extra id fields.

    Depends on: Algolia admin key and a Meilisearch host

    Stop / go checkpoint

    Copy hits?

    Go when: The primary key is chosen.

    Stop when: A revenue rule has no destination and no one will drop it.

  2. Days 3–5 · backup

    Export settings and hits

    4–8 hours active1–3 days elapsedBrowse runtime waiting
    • Save settings, synonyms, and rules.
    • Write hit counts.

    Depends on: Index list

    Stop / go checkpoint

    Load staging?

    Go when: Every index has a count and a settings file.

    Stop when: Browse missed an index the app still queries.

  3. Days 5–12 · pilot

    Stage the index

    12–30 hours active4–8 days elapsedTask queue waiting
    • Add documents with an explicit primary key.
    • Apply settings and compare the query list.

    Depends on: Hit files

    Stop / go checkpoint

    Shadow traffic?

    Go when: Counts match and signed queries look acceptable.

    Stop when: A batch failed on id inference or invalid ids.

  4. Days 12–16 · cutover

    Switch the client

    4–10 hours active1–3 days elapsedDeploy waiting
    • Point the app at Meilisearch.
    • Keep the Algolia write path until the queue is caught up.

    Depends on: Passed query review

    Stop / go checkpoint

    Stop Algolia writes?

    Go when: Production queries hit Meilisearch and the task queue is drained.

    Stop when: Updates are still landing only in Algolia.

  5. Days 15–22 · observe

    Watch updates

    4–8 hours active4–7 days elapsedA day of real updates waiting
    • Compare indexing lag with the Algolia baseline.
    • Keep Algolia until that lag is acceptable.

    Depends on: Client switch

    Stop / go checkpoint

    Close rollback?

    Go when: Updates keep up through a busy day.

    Stop when: The task queue falls hours behind.

07The point of change

Cut over with a way back.

Go live

Cutover

Serve queries from Meilisearch after counts, ids, and a signed query list pass.

Recommended window: After a staging query review, not during a merchandising campaign.

  1. Freeze the comparison set and re-browse Algolia for a final count.
  2. Add any new hits with the same primary key.
  3. Deploy the Instant Meilisearch adapter or the rewritten client.
  4. Watch the task queue through the next update batch.
  5. Leave the Algolia application in place.

Proof to capture: The app queries Meilisearch. Document counts match. Signed queries were reviewed.

Return to safety

Rollback

Point the client back at Algolia, which still has the records.

Deadline: Before you delete the Algolia application or the admin key.

  1. Deploy the previous Algolia client.
  2. Confirm queries return Algolia hits.
  3. Stop Meilisearch writes so a later retry does not diverge.
  4. Keep the id map and the settings JSON.
  5. Write down which queries disagreed.

Proof to capture: Production search uses Algolia again.

Rollback immediately when
  • Primary key task failed
  • Hit counts differ
  • A signed query's top result changed without approval
  • Update lag keeps growing
  • The UI still calls an Algolia parameter Meilisearch rejects
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingExplicit primary keyRead the index primary key after creation.It is objectID or the cleaned field you signed.Index JSON.
V-02BlockingCharacter scanReject objectIDs outside letters, digits, hyphens, and underscores.Zero illegal ids, or a rewrite map.Id report.
V-03BlockingHits per indexCompare Algolia nbHits with Meilisearch document count after the task succeeds.Counts match.Count sheet.
V-04BlockingFilters and sortsRun a faceted query and a replica sort.filterableAttributes and sortableAttributes cover them.Query log.
V-05BlockingSaved queriesCompare the top hits for the signed list, including a typo.Differences are listed and accepted.Query diff.
V-06Known pairsSearch both sides of a synonym such as yml and yaml.Pairs you kept return the same documents.Synonym sample.
V-07BlockingWidgetsClick every InstantSearch widget you still render.The adapter supports it, or you replaced it.UI notes.
V-08BlockingTask queueApply a production-sized update batch and read task status.Tasks succeed and lag stays inside the agreed bound.Task log.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: A busy day of updates with Algolia still able to take the client back.

  1. Archive settings, synonym exports, and the id rewrite map.
  2. Rotate the Algolia admin key you used to browse.
  3. Keep the Algolia app through the rollback window.
  4. Remove unused replica indexes from the app config only after cutover holds.
  5. Document the Meilisearch host and primary key.
  6. Schedule a ranking review after the first merchandising change.
10Experiences from the field

When the plan met reality.

First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.

First-person accountJavier Eguiluz · Symfony Blog

symfony.com left Algolia and split docs into Meilisearch section documents2023

Javier Eguiluz writes that symfony.com search had already used Solr, Elasticsearch, Google Custom Search, and Algolia. They left Algolia because JSON configuration did not give enough control over parsing, and readers reported confusing or missing results. They skipped the Symfony bundle because it targets Doctrine, and used the PHP client. Long RST pages were split into one document per section. The document id is an xxh3 hash of the URL, including the fragment, so a reindex updates in place. They parsed 12,754 files into 85,146 documents in 17 seconds. The index was about 1.2 GB, and most queries took under 10 milliseconds. Synonyms include yaml with yml, and symphony with symfony. He thanks Meilisearch for help and for hosting the index.

What they recommend
  • Split long pages into section documents when a whole-page hit is too vague for the query.
  • Set a stable id from the canonical URL so a later index run overwrites instead of duplicating.
Worth noticing
  • The move was about indexing control and result quality, after Algolia was already in production.
  • Meilisearch hosted the index. Eguiluz says so at the end of the post.

Meilisearch's case study says Qogita used Algolia and was satisfied with functionality and performance, then compared Meilisearch, Typesense, and Algolia. Relevancy was scored against Algolia's results, including typos and common misspellings. They self-hosted a proof of concept, then put production on Meilisearch Cloud because of cost and a small DevOps team. The article credits the Python library for the migration. Engineering director Ivo Silva is quoted on speed, relevancy, and local setup. Savings are called substantial, and the article does not give a number. The byline is Maya Shin at Meilisearch.

What they recommend
  • Score a short list of real queries against current Algolia results before you pick the replacement.
  • Decide self-hosted versus Meilisearch Cloud after the proof of concept. That is the order Qogita used.
Worth noticing
  • This is Meilisearch's case study. The quote and the savings wording come from them.
  • Typesense was in the comparison, and Meilisearch Cloud is what they say shipped.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. Meilisearch: migrate from AlgoliaAccessed 2026-11-01
  2. Meilisearch: primary keyAccessed 2026-11-01
  3. Algolia: export and import indicesAccessed 2026-11-01
  4. Symfony: search migration write-upAccessed 2026-11-01
  5. Hacker News: Meilisearch 1.0 indexing threadAccessed 2026-11-01