Index aliases in Elasticsearch keep client traffic pinned to one fixed name while the backing index changes underneath it. That makes rollovers, reindex cutovers, and staged validation possible without retargeting every shipper, dashboard, or application that writes to the cluster.
Aliases live in cluster state and are changed through the /_aliases API, which can add, remove, and swap bindings in a single atomic request. An alias can point to one or many indices, and setting is_write_index ensures indexing requests continue to land on the intended destination after a cutover.
Examples here use plain indices named logs-2025.03 and logs-2025.04 to avoid the built-in data stream patterns that current Elastic stacks reserve for names such as logs-*-*. Security-enabled clusters need the correct HTTPS endpoint plus authentication, and alias changes are safest only after the destination index has been populated, checked, and the cluster reports the expected health state.
Related: How to create an index in Elasticsearch
Related: How to reindex data in Elasticsearch
$ curl -sS --fail "http://localhost:9200/_cat/aliases/logs-*?v&h=alias,index,is_write_index" alias index is_write_index logs-current logs-2025.03 true
The _cat APIs are intended for human-readable terminal checks. Use the JSON-based /_alias endpoints in scripts or automation.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/_aliases?pretty" -d '{
"actions": [
{ "add": { "index": "logs-2025.04", "alias": "logs-next" } }
]
}'
{
"acknowledged" : true,
"errors" : false
}
A separate validation alias keeps production traffic on logs-current while queries or dashboards are checked against logs-next.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/_aliases?pretty" -d '{
"actions": [
{ "remove": { "index": "logs-2025.03", "alias": "logs-current", "must_exist": true } },
{ "add": { "index": "logs-2025.04", "alias": "logs-current", "is_write_index": true } }
]
}'
{
"acknowledged" : true,
"errors" : false
}
Setting must_exist on the remove action makes the request fail if the expected old alias binding is missing, which protects the cutover from stale assumptions about the current target.
Switch writes only after the destination index has the required mappings and document set.
$ curl -sS --fail "http://localhost:9200/_alias/logs-current?pretty&filter_path=*.aliases.*.is_write_index"
{
"logs-2025.04" : {
"aliases" : {
"logs-current" : {
"is_write_index" : true
}
}
}
}
On secured clusters, replace http://localhost:9200 with the cluster HTTPS endpoint and add authentication such as -u elastic:password or an API key header.
$ curl -sS --fail -H "Content-Type: application/json" -X PUT "http://localhost:9200/logs-current/_doc/alias-proof?refresh=wait_for&pretty" -d '{
"message": "alias write test",
"level": "info"
}'
{
"_index" : "logs-2025.04",
"_id" : "alias-proof",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
The returned _index value is the decisive proof that the write alias now points to the intended destination.
$ curl -sS --fail "http://localhost:9200/logs-2025.04/_doc/alias-proof?pretty&_source=message,level"
{
"_index" : "logs-2025.04",
"_id" : "alias-proof",
"_version" : 1,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"message" : "alias write test",
"level" : "info"
}
}
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/_aliases?pretty" -d '{
"actions": [
{ "remove": { "index": "logs-2025.04", "alias": "logs-next", "must_exist": true } }
]
}'
{
"acknowledged" : true,
"errors" : false
}
Keep the validation alias only when a staged consumer still needs it; otherwise remove it so application paths stay unambiguous.