Elasticsearch Reindex and Aliases

Some index decisions cannot change after creation. Primary shard count, field types, and analyzers stay fixed. Projects outgrow early choices, and the fix always follows the same route: build a new index with better settings, copy the data across, and switch the application over. The Reindex API performs the copy, and aliases perform the switch without any downtime.

The Reindex API

Reindex reads documents from a source index and writes them into a destination index. The destination must exist first, so create it with the new mapping and settings before copying.

PUT /products_v2
{
  "settings": { "number_of_shards": 3 },
  "mappings": {
    "properties": {
      "name":  { "type": "text" },
      "price": { "type": "float" }
    }
  }
}

POST /_reindex
{
  "source": { "index": "products_v1" },
  "dest":   { "index": "products_v2" }
}
  products_v1                      products_v2
  (old mapping, 1 shard)   ───→    (new mapping, 3 shards)
        │                                 │
   still serving users              being filled in the background

Copying Only Part of the Data

A query inside the source section selects a subset. The script option changes documents on the way through.

POST /_reindex
{
  "source": {
    "index": "products_v1",
    "query": { "term": { "active": true } }
  },
  "dest": { "index": "products_v2" },
  "script": {
    "source": "ctx._source.price = ctx._source.price * 1.1"
  }
}

Running Large Copies in the Background

Big indexes take minutes or hours. Set wait_for_completion to false, and Elasticsearch returns a task ID immediately. Check progress through the Tasks API.

POST /_reindex?wait_for_completion=false&slices=auto
{ "source": { "index": "products_v1" }, "dest": { "index": "products_v2" } }

Response: { "task": "oTUltX4IQMOUUVeiohTt8A:12345" }

GET /_tasks/oTUltX4IQMOUUVeiohTt8A:12345

The slices=auto setting splits the work into parallel pieces, one per shard. Throughput rises sharply on multi-node clusters.

What an Alias Does

An alias is a second name for one or more indexes. Applications talk to the alias, and the real index behind it can change at any moment. Think of a shop sign that says "Open." Staff swap the actual room behind the door, and customers never notice.

Application  ──→  alias "products"  ──→  products_v1
POST /_aliases
{
  "actions": [
    { "add": { "index": "products_v1", "alias": "products" } }
  ]
}

The Zero-Downtime Switch

A single _aliases request can remove one index from an alias and add another. Elasticsearch applies all actions in the request as one atomic step. No moment exists where the alias points nowhere.

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" } },
    { "add":    { "index": "products_v2", "alias": "products" } }
  ]
}

Before:  products ──→ products_v1
After:   products ──→ products_v2     (switch happens instantly)

The Complete Migration Recipe

StepAction
1Point the application at the alias "products"
2Create products_v2 with the improved mapping
3Reindex from products_v1 to products_v2
4Compare document counts of both indexes
5Swap the alias in one atomic request
6Keep products_v1 for a few days as a safety net, and delete it afterward

New documents that arrive during the copy exist only in the old index. Pause writes briefly before the swap, or run a second reindex that copies only documents newer than the first run.

Filtered Aliases

An alias can carry a filter. Each alias shows a slice of the same index, which helps multi-tenant systems and department views.

POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "orders",
        "alias": "orders_europe",
        "filter": { "term": { "region": "europe" } }
      }
    }
  ]
}

Write Index and Multiple Indexes

An alias can span several indexes for searching. Only one index may accept writes, marked with is_write_index. Time-based setups use this pattern: searches cover all monthly indexes, while writes go to the newest one.

alias "logs"  ──→  logs-2026.09   (read only)
              ──→  logs-2026.10   (read only)
              ──→  logs-2026.11   (is_write_index: true)

List every alias with GET /_cat/aliases?v. The output shows which indexes hide behind each name.

Checking the Result

Compare counts after every reindex. A mismatch signals documents that failed to copy, and the response of the reindex call lists failures and version conflicts. Spot-check a few documents by ID in both indexes, and run a handful of real searches against the new index before moving the alias.

GET /products_v1/_count
GET /products_v2/_count

Both responses should show the same count value.

Version conflicts occur when the destination already holds a document with the same ID. Set conflicts to proceed in the request body when a rerun should skip existing documents instead of stopping.

Naming Habits

Treat index names as internal details and alias names as the public contract. Applications, dashboards, and scripts use the alias. Index names carry a version suffix such as _v1 and _v2, so engineers see at a glance which generation serves traffic. This habit turns a risky migration into a routine task.