Why do the migration in Kestra
A hand-rolled scroll-and-push script has no memory: kill it mid-run and you don’t know what transferred, and there’s no retry. Kestra makes the migration an observable, resumable-by-re-run workflow. The export streams to disk, indexing batches and waits for completion, and every run is logged. Re-run it as often as you like during cutover.Prerequisites
A running Kestra with the Meilisearch and OpenSearch plugins, plus a Meilisearch Cloud project. Only Kestra runs locally, since Meilisearch is managed:Get your Cloud credentials. In the Meilisearch Cloud dashboard, create a project and copy its Project URL (the
url in the flows below) and its Default Admin API Key (Settings, then API Keys). Store the key as the MEILISEARCH_API_KEY Kestra secret.movies index of documents like { "id": 3, "title": "Parasite", "year": 2019, "genre": "thriller" }.
Step 1: Backfill the whole index
The OpenSearch plugin’sScroll task walks the entire index and writes every document to an ION file in internal storage, the exact format the Meilisearch DocumentAdd task reads. Two tasks migrate the whole index:
Scroll streams to disk, so it scales to very large indexes. DocumentAdd batches and waits for indexing, failing loudly on any error. Meilisearch uses each document’s id field as the primary key. If yours lives only in _id, copy it into a real field with a JSONata TransformItems step first.
Run it once and the whole index is searchable in Meilisearch.
Step 2: Cut over safely
Do it gradually, not all at once:- Backfill into Meilisearch with the flow above.
- Dual-run a Meilisearch-backed copy of your search UI next to production and compare relevance and latency on real queries.
-
Keep it fresh during the overlap. Re-run the backfill on a schedule, or scroll only recent changes if your documents carry a timestamp:
Overlapping runs are safe because
DocumentAddis add-or-replace: re-indexing a document just overwrites it by primary key. - Flip production to Meilisearch once you trust the results, and retire the OpenSearch cluster.
A note on deletes
For a one-time snapshot migration, deletes are moot. If documents are removed during a long dual-run, reconcile by indexing each fresh backfill into a new Meilisearch index and repointing an alias at it, so anything absent from the latest scroll disappears. Kestra can run that index-then-swap as one flow.Going to production
- Secured clusters: add
basicAuth(or an API-key header) to theconnection, with the password from a Kestra secret. SettrustAllSsl: trueonly for self-signed dev clusters. - Reshape while migrating with a JSONata
TransformItemsstep betweenscrollandindex_documentsto rename fields, flatten, and drop noise. - Set Meilisearch index settings first (searchable, filterable, and sortable attributes via an
http.Requestto the settings API) so the first pass ranks well. - Retries. Add a
retryblock so a transient hiccup during a long scroll is retried instead of failing the migration.
Wrap-up
Migrating off OpenSearch isScroll to export plus DocumentAdd to index, wrapped in a re-runnable Kestra workflow that supports a safe, gradual cutover. The flow is byte-identical to the Elasticsearch one apart from the plugin name, proof of how uniform the extract-to-index pattern is across sources.