Reindexing in Elasticsearch copies documents into a new index so mapping changes, field additions, analyzer updates, and shard-layout changes can be applied without rewriting data in place. Keeping the original index intact makes rollback, comparison, and controlled cutovers possible while the new layout is still being validated.
The _reindex API reads documents from a source index, alias, or data stream and writes them into a separate destination with bulk indexing. The request can filter the source set, transform documents with a Painless script, and run asynchronously so the job can be tracked through the _tasks API instead of holding one long client request open.
The destination index must already have the wanted mappings and settings because _reindex does not clone them from the source, and the source documents must have _source enabled. Security-enabled clusters also need source read and destination write privileges. Current Elastic stacks ship built-in data stream templates for patterns such as logs-*-*, so this example uses neutral index names to avoid accidental data stream routing while demonstrating plain index-to-index reindexing. Reindexing is safest while cluster health is GREEN and source writes are paused for the final cutover pass.
$ curl -sS --fail -H "Content-Type: application/json" -X PUT "http://localhost:9200/orders-2026.04-v2?pretty" -d '{
"settings": {
"number_of_replicas": 0
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"status": { "type": "keyword" },
"message": { "type": "wildcard" },
"message_length": { "type": "integer" }
}
}
}'
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "orders-2026.04-v2"
}
This keeps the worked example GREEN on a single-node cluster by setting number_of_replicas to 0. Increase the replica count when the destination should keep a replica on another data node.
Names that match built-in data stream patterns such as logs-*-* can be claimed by managed templates on current clusters. Use a non-overlapping index name or an explicit higher-priority template when the destination must remain a plain index instead of a data stream.
$ curl -sS --fail "http://localhost:9200/orders-2026.04/_count?pretty"
{
"count" : 3,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
}
}
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/_reindex?wait_for_completion=false&refresh=true&pretty" -d '{
"source": {
"index": "orders-2026.04"
},
"dest": {
"index": "orders-2026.04-v2",
"op_type": "create"
},
"script": {
"lang": "painless",
"source": "ctx._source.message_length = ctx._source.message.length()"
}
}'
{
"task" : "OR67Y7F4SB6kagwvDX_j6g:847"
}
This example adds a new message_length field while copying documents. Keeping op_type set to create prevents existing destination IDs from being overwritten silently, and the same setting is required when the destination is a data stream.
Writes accepted by the source index after the scroll search starts are not guaranteed to appear in the destination index. Pause writes or plan a final short reindex window before cutover when exact parity matters.
$ curl -sS --fail "http://localhost:9200/_tasks/OR67Y7F4SB6kagwvDX_j6g:847?wait_for_completion=true&pretty&filter_path=completed,response.total,response.created,response.updated,response.version_conflicts,response.failures"
{
"completed" : true,
"response" : {
"total" : 3,
"updated" : 0,
"created" : 3,
"version_conflicts" : 0,
"failures" : [ ]
}
}
The _tasks response is the fastest place to confirm whether the run finished cleanly. If reruns should continue past duplicate IDs, add \"conflicts\": \"proceed\" to the original reindex request and review the version_conflicts count carefully.
$ curl -sS --fail "http://localhost:9200/orders-2026.04-v2/_count?pretty"
{
"count" : 3,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
}
}
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/orders-2026.04-v2/_search?pretty&size=1&sort=%40timestamp:desc&filter_path=hits.hits._id,hits.hits._source" -d '{
"query": {
"match_all": {}
}
}'
{
"hits" : {
"hits" : [
{
"_id" : "a3",
"_source" : {
"@timestamp" : "2026-04-02T05:06:00Z",
"message_length" : 14,
"message" : "proof captured",
"status" : "delivered"
}
}
]
}
}
After the destination index is validated, switch application traffic with an alias rather than renaming client targets one by one.