← All playbooks
Hosted search migration

Elastic Cloud → Meilisearch

Copy an Elastic Cloud index into Meilisearch with a point-in-time read, put _id on the document, and flatten nested fields. Analyzers and cluster security do not come with the documents.

Typical timeline1 to 3 weeks16 to 40 hours active work
Statusneeds review
Source profileMeilisearch Elasticsearch migration guide, including its Elastic client examples, reviewed 2026-11-03
Destination profileMeilisearch Elasticsearch migration and Kestra cutover docs reviewed 2026-11-03
Documentation date
Review window
Evidence2 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

Elastic Cloud

Reasons to stay
  • Managed Elasticsearch delivers powerful full-text, vector, analytics, and observability capabilities at scale
  • Managed indexing, relevance, filtering, and globally available query APIs reduce search operations
Reasons to leave
  • Mappings, analyzers, cluster sizing, upgrades, and query complexity require search expertise
  • 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: Mappings, analyzers, cluster sizing, upgrades, and query complexity require search expertise.

Worst of the move

What you lose: Managed Elasticsearch delivers powerful full-text, vector, analytics, and observability capabilities at scale. 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 outcome11 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 4, Manual rebuild: 4, Not transferred: 3.
Clean0
Partial4
Manual4
Lost3
Mapping route9 of 9 fields have a destination path

This timeline assumes

  • The source is an Elasticsearch index on Elastic Cloud, reached with the Elasticsearch client.
  • You want application search, not a copy of Kibana, ingest pipelines, or index lifecycle policies.
  • You can run Meilisearch or Meilisearch Cloud beside Elastic Cloud until queries match well enough.
  • The site already documents Elastic Cloud → Algolia and Elastic Cloud → Typesense Cloud.
02What transfers

What survives the move.

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

ItemOutcomeImpactWhat happensMitigation
DocumentspartialcriticalMeilisearch's guide pages an index with the Point in Time API and search_after, which it prefers to the deprecated Scroll API. It reads hits in batches of 10,000, then uploads with addDocumentsInBatches in batches of 100,000.Count documents on both sides. Re-run is safe if the same primary key overwrites.
Primary keymanualcriticalElasticsearch wraps the document in _id, _index, and _source. Meilisearch needs a primary key on the document. The guide copies _id onto id.Do that copy before upload. A missing id collapses updates.
Nested objectspartialcriticalMeilisearch stores flat JSON. Nested mappings have to be flattened. Only top-level fields can be filtered, sorted, or searched. The guide's example turns author.name into author_name, or leaves the object for display only.List every nested field you filter on and flatten those before the full upload.
Keyword and text mappingspartialhighMeilisearch infers types and searches all fields unless you set searchableAttributes. Keyword fields you want to facet belong in filterableAttributes. index: false maps to displayedAttributes in their comparison table.Set filterable attributes before you judge facets. A filter on a field that is not filterable will fail.
AnalyzerslosthighMeilisearch says custom analyzers and tokenizers are not copied. Stemming, Unicode, and language detection are built in. Stop words, synonyms, and separator tokens are the settings you recreate. Localized fields use localizedAttributes.Run the queries you care about on both engines. Do not expect the same ranking.
Query DSLmanualcriticalBool queries with must, should, and filter become a q string plus a filter. geo_point becomes a _geo field with lat and lng, and it must be filterable and sortable for radius and bounding-box filters.Rewrite each production query. Keep Elastic Cloud serving until the new queries pass.
Elastic Cloud authmanualhighThe Kestra guide tells you to add basic auth for Elastic Cloud, with the username elastic and the password in a secret. The open migration script will not reach a locked cluster without credentials.Use a key you can revoke. Do not put the elastic password in the app that serves search.
Shards, replicas, and ILMlostmediumMeilisearch's comparison says replicas, shards, and index lifecycle do not have the same knobs. Meilisearch Cloud manages that layer. A self-hosted process is one process.Size Meilisearch for the index you measured. Do not copy shard counts across.
Security roles and API keysmanualcriticalElastic Cloud roles do not become Meilisearch keys. The guide uses the admin key for the load, which is the wrong key for the public app.Create a search-only key for the app. Revoke the admin key from any client bundle.
Deletes during dual-runpartialhighThe Kestra guide says a one-shot copy ignores later deletes. If both sides run for a while, index each fresh backfill into a new Meilisearch index and move an alias, so missing documents disappear.Either freeze writes for the copy, or use a new index plus an alias at cutover.
Kibana and pipelineslostmediumThe migration guide moves documents and compares search settings. It does not move dashboards, alerts, or ingest pipelines.Keep Elastic Cloud if you still need those. This move is the search index.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
_sourceMeilisearch documenttransformDrop the Elasticsearch wrapper.
_ididtransformCopy it onto the document before upload.
nested objectTop-level fieldstransformFlatten anything you filter or sort.
keyword fieldfilterableAttributesmanualAdd it before facet queries.
text fieldsearchableAttributesmanualAll fields are searchable until you restrict them.
geo_point_geotransformlat and lng. Mark it filterable and sortable.
synonyms and stop wordssynonyms and stopWordsmanualRecreate the lists. Analyzers do not import.
bool queryq and filtertransformRewrite production queries one by one.
Elastic Cloud credentialsClient basic auth or an API keymanualKestra's note uses username elastic. Revoke it after the load.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep Elastic Cloud serving and keep a snapshot of the index you copied.

  1. Record index names, mappings, synonyms, and the queries in production.
  2. Confirm you can open a point in time against the Elastic Cloud endpoint.
  3. Note document counts per index.
  4. Keep Elastic Cloud as the live engine until the Meilisearch pilot matches.
  5. Store the API key in a secret manager, not in the migration script you commit.

Proof to capture: You have counts, mappings, and a revoked-key plan before the first full upload.

Transformation · Meilisearch's Elasticsearch migration script

Document load

Read the Elastic Cloud index and add documents to Meilisearch.

  1. Point the Elasticsearch client at Elastic Cloud with basic auth or an API key.
  2. Page with a point in time and search_after, 10,000 hits at a time.
  3. Copy _id to id and flatten nested fields you must filter.
  4. Upload in batches of 100,000 and wait until the task succeeds.

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

Transformation · Index settings and a feature flag

Settings and cutover

Make facets and queries behave, then switch reads.

  1. Set filterableAttributes, searchableAttributes, synonyms, and stop words.
  2. Run the same queries against both engines.
  3. During an overlap, follow Kestra's advice: backfill on a schedule, or filter on updated_at.
  4. Cut reads over by pointing an alias at a fresh index if deletes happened during the overlap.

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

Documents have no stable id

criticalpossible likelihood

_id stayed in the hit metadata and never landed on the document.

Consequence
Updates insert duplicates or Meilisearch rejects the batch.
Mitigation
Map _id to id in the prepare step the guide shows.

Stop if: A second run changes the document count when it should only overwrite.

Pilot

Facets query fields that are not filterable

highlikely likelihood

A keyword mapping was never added to filterableAttributes.

Consequence
Filters error or silently fail to narrow results.
Mitigation
Add the attribute, then re-run the query.

Stop if: A production filter has no filterable attribute.

Cutover

Reads move before relevance is checked

highpossible likelihood

The index is full and nobody compared a real query.

Consequence
Ranking changes for the queries that pay the bills.
Mitigation
Dual-run behind a flag, as the Kestra guide describes.

Stop if: You have not compared the top queries.

06Precise timeline

Do the work in this order.

Estimate forOne application index on Elastic Cloud, with nested fields and a known query list
Total elapsed1 to 3 weeks
Active work16 to 40 hours
BufferAdd time for many indexes, heavy nested documents, or a long dual-run while deletes keep landing.
01
Days 1 to 3Mappings and queries2 to 3 days
02
Days 3 to 4Counts and keys1 day
03
Days 4 to 10One index beside production4 to 7 days
04
Days 10 to 12Switch reads1 to 2 days
05
Days 12 to 19Watch relevance7 days
  1. Days 1 to 3 · inventory

    Mappings and queries

    4 to 8 hours active2 to 3 days elapsedOwner picks the query list waiting
    • Export mappings and the production queries.
    • Mark nested fields and geo points.

    Depends on: Elastic Cloud credentials and a Meilisearch admin key

    Stop / go checkpoint

    Copy documents?

    Go when: Each filter field has a flatten or filterable plan.

    Stop when: You still need Kibana or ingest pipelines from this move.

  2. Days 3 to 4 · backup

    Counts and keys

    2 to 4 hours active1 day elapsedNone waiting
    • Record document counts.
    • Store credentials outside the repo.

    Depends on: Inventory

    Stop / go checkpoint

    Pilot index?

    Go when: You can open a point in time.

    Stop when: Auth to Elastic Cloud fails.

  3. Days 4 to 10 · pilot

    One index beside production

    8 to 20 hours active4 to 7 days elapsedIndexing tasks waiting
    • Load a pilot index.
    • Set filterable attributes.
    • Compare the top queries.

    Depends on: Counts

    Stop / go checkpoint

    Dual-run?

    Go when: Counts match and the query list is acceptable.

    Stop when: Nested filters still fail.

  4. Days 10 to 12 · cutover

    Switch reads

    3 to 6 hours active1 to 2 days elapsedAlias move waiting
    • Final backfill into a fresh index if deletes matter.
    • Point the app at Meilisearch.
    • Keep Elastic Cloud read-only for a rollback read.

    Depends on: Query sign-off

    Stop / go checkpoint

    Meilisearch serves search?

    Go when: Production queries hit Meilisearch only.

    Stop when: A top query regresses.

  5. Days 12 to 19 · observe

    Watch relevance

    2 to 4 hours active7 days elapsedReal queries waiting
    • Sample zero-result queries.
    • Keep the Elastic Cloud index until you accept ranking.

    Depends on: Cutover

    Stop / go checkpoint

    Retire the index?

    Go when: A week of queries is acceptable and counts still match.

    Stop when: You need the old ranking back.

07The point of change

Cut over with a way back.

Go live

Cutover

The app reads Meilisearch. Elastic Cloud is still there if ranking is wrong.

Recommended window: A period you can flip the feature flag back without a deploy freeze.

  1. Freeze writes or start the alias-based backfill.
  2. Confirm document counts.
  3. Point search reads at Meilisearch.
  4. Watch errors on filterable attributes.
  5. Leave Elastic Cloud queryable until the observation window ends.

Proof to capture: Production search hits Meilisearch, counts match, and the top queries were compared.

Return to safety

Rollback

Point search reads back at Elastic Cloud.

Deadline: Before you delete the Elastic Cloud index or deployment.

  1. Flip the flag or client back to Elastic Cloud.
  2. Stop Meilisearch writes if you were dual-writing.
  3. Keep the Meilisearch index for the next attempt.
  4. Revoke any temporary elastic user password you created for the load if you are done with it.
  5. Re-run the query list against Elastic Cloud.

Proof to capture: Search traffic is on Elastic Cloud again and the index you did not delete still answers.

Rollback immediately when
  • Document counts diverge
  • A filter errors because an attribute is not filterable
  • Ranking on a top query is unacceptable
  • The public client is using the admin key
  • Deletes during dual-run left stale documents and you did not swap the alias
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-01BlockingDocument totalsCompare the index count with Meilisearch stats.They match after the task finishes.Count note.
V-02Blockingid equals _idFetch ten documents from both sides.The Meilisearch primary key is the old _id.Sample JSON.
V-03BlockingFlattened filtersFilter on a field that used to be nested.The filter returns the same ids you expect, or you have accepted display-only.Query pair.
V-04BlockingfilterableAttributesRun each production filter.No error about a non-filterable attribute.Query log.
V-05_geoRun a radius query if you had geo_point._geo is filterable and sortable, or geo is out of scope.Query result.
V-06BlockingSearch keyCall search with the app key and with the admin key removed from the client.Search works. The admin key is not in the app.Client config.
V-07BlockingTop queriesCompare the query list on both engines.An owner has accepted the differences.Query sheet.
V-08BlockingElastic Cloud still answersRun one query against the old index.It returns hits until you delete the deployment.Query response.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: A week of accepted Meilisearch queries and a matching document count.

  1. Revoke the Elastic Cloud credential used for the dump.
  2. Rotate the Meilisearch admin key if it was pasted into a script.
  3. Delete pilot indexes you did not alias.
  4. Keep Elastic Cloud until the rollback date you wrote down.
  5. Remove the dual-read flag after that.
  6. Review synonyms the next time ranking complaints show up.
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 ElasticsearchAccessed 2026-11-03
  2. Meilisearch: migrate Elasticsearch with KestraAccessed 2026-11-03