An alias in Elasticsearch is a secondary pointer to one or more indices. Applications query and write against the alias name; Elasticsearch routes the request to the underlying index. Aliases make reindexes, rollovers, and migrations invisible to the application: you swap which index the alias points at, and the application keeps talking to the same name. Any production cluster should have application code pointing at aliases, not direct index names. Aliases work the same on Elasticsearch 7.x, 8.x, and 9.x, and on OpenSearch with identical syntax.
This guide covers the aliases API, the atomic-swap pattern for zero-downtime reindexes, write aliases with is_write_index, filtered aliases for multi-tenant data, and the rollover pattern.
Creating and Querying Aliases
The simplest way to attach an alias to an index:
POST /_aliases
{
"actions": [
{ "add": { "index": "products-v1", "alias": "products" } }
]
}
You can also create an alias at index creation time:
PUT /products-v1
{
"aliases": { "products": {} }
}
Or via an index template, so the alias is applied automatically to every matching index.
Inspect:
GET /_alias
GET /_alias/products
GET /products-v1/_alias
The Atomic Alias Swap
This is the bread-and-butter pattern: switch which index a name points at with no gap during which the alias is missing. Use a single _aliases request with both actions:
POST /_aliases
{
"actions": [
{ "remove": { "index": "products-v1", "alias": "products" } },
{ "add": { "index": "products-v2", "alias": "products" } }
]
}
Elasticsearch applies the entire actions array atomically. There is no instant where the products alias is undefined. This is the right tool for finishing a reindex migration, swapping in a re-mapped index, or rolling forward after a successful blue-green cutover.
The Zero-Downtime Reindex Pattern
The end-to-end shape of a reindex that does not interrupt application traffic:
# 1. Application is already pointing at the `products` alias.
# `products` currently maps to `products-v1`.
# 2. Create a new index with the corrected mapping.
PUT /products-v2
{
"settings": { /* ... */ },
"mappings": { /* corrected mappings */ }
}
# 3. Backfill data.
POST /_reindex
{
"source": { "index": "products-v1" },
"dest": { "index": "products-v2" }
}
# 4. (Optional) Verify document counts and run a smoke test against products-v2 directly.
# 5. Atomic swap: cut application reads to the new index in one request.
POST /_aliases
{
"actions": [
{ "remove": { "index": "products-v1", "alias": "products" } },
{ "add": { "index": "products-v2", "alias": "products" } }
]
}
# 6. After a cool-off period (a day, a week), delete the old index.
DELETE /products-v1
If the application is writing during the reindex, you have two extra steps: use a write alias with is_write_index (below), or pause writes for the swap. For high-throughput write loads, is_write_index plus catch-up reindex is the standard approach.
For the full background on reindexing, see the reindex guide. For deletion semantics, see delete index.
Write Aliases: is_write_index
A single alias can point at multiple indices, but writes need a single destination. The is_write_index flag tells Elasticsearch which one:
POST /_aliases
{
"actions": [
{ "add": { "index": "logs-2026-05-13", "alias": "logs", "is_write_index": false } },
{ "add": { "index": "logs-2026-05-14", "alias": "logs", "is_write_index": true } }
]
}
Now POST /logs/_doc writes go to logs-2026-05-14. Reads (search, get) span both indices. This is what makes the rollover pattern work without application changes: the alias is the stable name, and Elasticsearch quietly moves the write target forward as rollover happens.
Note: data streams supersede this pattern in many cases. If you are starting fresh on a time-series workload, prefer a data stream over a rollover alias.
Filtered Aliases (Multi-Tenant Views)
A filtered alias applies a query filter every time it is read. This lets you give a tenant or use case a stable, filtered view over a shared index:
POST /_aliases
{
"actions": [
{
"add": {
"index": "events",
"alias": "events-tenant-acme",
"filter": { "term": { "tenant_id": "acme" } }
}
}
]
}
Every search against events-tenant-acme adds the tenant_id: acme filter automatically. Useful for multi-tenant search, security boundaries, and pre-filtered analytics views.
Two caveats:
- Filtered aliases are not a security primitive on their own. They prevent accidental cross-tenant reads but do not stop a malicious actor who can issue queries against the underlying index. Pair with document- and field-level security for real isolation.
- The filter adds a clause to every query, which costs a tiny amount of latency. For high-throughput workloads, profile before rolling it out broadly.
Routing Aliases
You can attach a routing or search_routing/index_routing value to an alias:
POST /_aliases
{
"actions": [
{
"add": {
"index": "events",
"alias": "events-tenant-acme",
"search_routing": "acme",
"index_routing": "acme"
}
}
]
}
Now reads and writes through this alias hit only the shard that acme would route to. This pairs naturally with custom routing schemes for tenanted data and can cut search latency dramatically on large clusters.
Inspecting Aliases
# Every alias on the cluster
GET /_alias
# A specific alias
GET /_alias/products
# All aliases pointing at a given index
GET /products-v1/_alias
# Through the cat API
GET /_cat/aliases?v
GET /_cat/aliases/logs*?v
The cat form returns a table including the underlying index, is_write_index, filter, and routing. Useful for one-shot audits.
Aliases in an Index Template
To apply an alias to every index that matches a template:
PUT /_index_template/logs-template
{
"index_patterns": ["logs-*"],
"template": {
"aliases": {
"logs-all": {}
}
}
}
Every logs-* index will automatically join the logs-all alias. For data streams, this pattern is replaced by the data stream itself.
Common Pitfalls
- Mixing alias and index names. Aliases and indices share a namespace. You cannot have an index named
productsand an alias namedproductsat the same time. If you try, Elasticsearch rejects the operation. Pick a clear naming convention up front (productsfor the alias,products-v1,products-v2for the indices). - Forgetting
is_write_indexwhen multiple indices share an alias. Writes will be rejected withno write index is defined for alias. Mark exactly one underlying index as the write index. - Pointing applications directly at indices. This is the single biggest reason teams cannot reindex without downtime. Always point at the alias.
- Filtered alias without testing the filter. A misconfigured filter silently returns zero results. Always run a sanity-check query after creating one.
- Deleting an alias when you meant to delete the index. The API is symmetric (
DELETE /<index>/_alias/<name>removes the alias only, butDELETE /<index>removes the underlying data). Reread the command before pressing enter.
How Pulse Helps With Alias Hygiene
Aliases done right are invisible; aliases done wrong are silent disasters. The most common alias problems we see at Pulse are: applications still pointing at raw index names instead of aliases, aliases that span far more indices than their owners realize (because rollover stopped pruning), write aliases without an is_write_index flag, and filtered aliases whose filters no longer match the data shape. Pulse continuously inspects alias topology on Elasticsearch and OpenSearch clusters and flags these issues before they cause a 3 a.m. incident. Connect your cluster to Pulse and let the alias audits happen automatically.
Frequently Asked Questions
Q: Can an alias point at multiple indices?
Yes. A single alias can span any number of underlying indices. For reads, the alias behaves like a multi-index search target. For writes, exactly one of the underlying indices must be marked is_write_index: true, or writes will fail.
Q: Is creating or removing an alias atomic across multiple changes?
Yes, if you put all the changes in a single _aliases request. The entire actions array applies atomically. Splitting into multiple requests does not give you atomicity.
Q: Does an alias hurt query performance?
For an unfiltered alias on one index, the overhead is essentially zero. For a filtered alias, the alias filter is added as a clause to every query, adding a small amount of latency. For most workloads it is negligible.
Q: Can I rename an index by using an alias?
Sort of. There is no rename API. The pattern is to attach an alias with the new name to the existing index, point applications at the alias, and either keep the underlying index name or clone or reindex under a new name later.
Q: What is the difference between an alias and a data stream?
A data stream is a managed abstraction over a series of backing indices that handles rollover, write routing, and append-only semantics natively. An alias is a more general pointer that you manage yourself. For time-series workloads, data streams are the recommended choice. For everything else (reindex migrations, multi-tenant views, multi-index reads), aliases are the right tool.
Q: Can I have an alias on a closed index?
Yes, but writes will fail because the index is closed. Reads through the alias will see the closed index as unavailable. Most teams do not put aliases on closed indices because the alias makes the closed state easy to overlook.