Elasticsearch to OpenSearch: what actually differs

OpenSearch forked from Elasticsearch 7.10 in 2021, and every year since has widened the gap. Both are excellent engines; a move between them in either direction is a real migration, not a repoint. When we scope one, this is the checklist of differences we walk — because the surprises cluster in the same half-dozen places every time.

Start from why

The honest drivers are usually license posture (a preference for Apache-2.0 all the way down), platform gravity (deep AWS shops toward Amazon OpenSearch Service; Elastic Cloud shops the other way), or a feature on exactly one side — ES|QL and Elastic's ML/AIOps features on one, OpenSearch's plugin openness and license simplicity on the other. Write the driver down first: it decides how much friction is worth absorbing, and it tells you which of the differences below are decisive rather than merely annoying.

Clients and compatibility

This is the first practical wall. Modern Elastic clients check the server they talk to and refuse non-Elastic backends, so a move to OpenSearch means moving to the OpenSearch clients (opensearch-py, opensearch-java, and friends) — a dependency change across every service that touches the cluster. Inventory those services early; in most estates there are more than anyone remembers, and a few are in languages nobody admits to. Tooling with hardcoded Elastic assumptions (custom health checks, deploy scripts, Terraform providers) belongs on the same inventory.

Security model

Elasticsearch security is X-Pack: API keys, role mappings, realms configured in Elastic's way. OpenSearch ships the opensource security plugin: its own roles.yml/API, its own tenancy concept in Dashboards, different fine-grained access control semantics. Nothing maps one-to-one. Plan to redesign roles and authentication deliberately rather than translating configs line by line — and test service-account permissions against real request patterns, because that's where a translated policy fails quietly.

Query languages and features

The shared core — query DSL, aggregations, mappings — remains highly compatible; the divergence is at the edges:

  • ES|QL is Elastic-only; OpenSearch has PPL and its own SQL plugin. Anything built on one has no direct equivalent on the other.
  • Vector search differs materially: both do kNN, but engine options, index types, quantization, and tuning parameters are different enough that a tuned vector deployment must be re-benchmarked, not ported.
  • Ingest and enrich pipelines mostly translate, but processor inventories differ at the margins — diff yours against the target's list.
  • Alerting, ML, SIEM features are entirely parallel universes. Detection rules, anomaly jobs, and watches all need rebuilding in the target's idiom.

Kibana vs OpenSearch Dashboards

Dashboards forked from Kibana 7.10 too, and years of Kibana development since (Lens evolution, Discover rewrites, Fleet UI) have no counterpart. Saved objects export/import works for the basics; complex Lens visualizations, Canvas workpads, and anything Fleet-related will not come across. Budget real time to rebuild the dashboards people actually use — and treat it as a chance to delete the ones nobody does.

Snapshots: the one-way valves

Snapshot compatibility is where physics constrains the plan. OpenSearch can restore snapshots from Elasticsearch up to 7.10-era indices; it cannot restore snapshots from post-fork Elasticsearch versions, and Elasticsearch cannot restore OpenSearch snapshots. In practice, a modern-Elasticsearch-to-OpenSearch move (or the reverse) transfers data by reindex-from-remote or replay from the source stream, not by snapshot restore. For big estates that means planning around reindex throughput, and it makes the migration a natural moment for the mapping cleanup you've been deferring — you're rewriting every document anyway.

How we run the move itself

The pattern that works is parallel-run: stand up the target, dual-ship new data (easy for observability streams — point the collectors at both), backfill history by reindex where it's worth carrying, and reconcile counts and spot-check queries before cutting readers over. Time-series estates get a cheaper variant: ship new data to the target and simply let retention age the old cluster out, keeping it read-only until its last index expires. Either way, cutover becomes a routing change you can undo — which is the property that separates a migration from a gamble.

The short version

The engine core carries over; the perimeter — clients, security, dashboards, vector tuning, and every value-add feature — is where the work lives, and snapshots won't save you across the fork. Inventory the perimeter honestly and the project sizes itself.