Index rollover keeps long-running Elasticsearch ingest targets from growing into one oversized index, which helps preserve recovery speed, shard efficiency, and predictable query performance as event volume rises.
Alias-based rollover uses one alias for writes and, when historical generations should stay searchable under one name, a second alias for reads. The write alias points to the current concrete index with is_write_index set, and the rollover API creates the next zero-padded generation when the configured condition is met.
Current Elastic guidance recommends data streams for new append-only time-series projects, but alias-based rollover remains useful when classic indices are still required or documents must be updated by index name. Common patterns such as logs-* can also collide with built-in templates and lifecycle assets on current clusters, so this example uses rollover-demo-*. Secured clusters need the correct HTTPS endpoint plus authentication options in curl, and repeated rollovers should inherit mappings and settings from a matching index template or from the rollover request body.
$ curl -sS --fail -H "Content-Type: application/json" -X PUT "http://localhost:9200/rollover-demo-000001?pretty&filter_path=acknowledged,shards_acknowledged,index" -d '{
"settings": {
"number_of_replicas": 0
},
"aliases": {
"rollover-demo-write": {
"is_write_index": true
},
"rollover-demo": {}
}
}'
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "rollover-demo-000001"
}
This example sets number_of_replicas to 0 so a one-node validation cluster stays GREEN. The zero-padded suffix lets Elasticsearch derive rollover-demo-000002 automatically, and the separate rollover-demo alias keeps older generations searchable after the write target moves.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/rollover-demo-write/_doc?refresh=wait_for&pretty&filter_path=_index,_id,result" -d '{
"@timestamp": "2026-04-02T07:20:00Z",
"message": "pre-rollover event"
}'
{
"_index" : "rollover-demo-000001",
"_id" : "LM4BTZ0BJgxRBVGyAREe",
"result" : "created"
}
Applications keep writing to rollover-demo-write while the backing index generation changes underneath it.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/rollover-demo-write/_rollover?dry_run=true&pretty" -d '{
"conditions": {
"max_docs": 1
},
"settings": {
"number_of_replicas": 0
},
"aliases": {
"rollover-demo": {}
}
}'
{
"acknowledged" : false,
"shards_acknowledged" : false,
"old_index" : "rollover-demo-000001",
"new_index" : "rollover-demo-000002",
"rolled_over" : false,
"dry_run" : true,
"lazy" : false,
"conditions" : {
"[max_docs: 1]" : true
}
}
dry_run=true only evaluates the condition result, so acknowledged and rolled_over stay false. Including settings and aliases here previews the shape of the index that the real rollover should create.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/rollover-demo-write/_rollover?pretty" -d '{
"conditions": {
"max_docs": 1
},
"settings": {
"number_of_replicas": 0
},
"aliases": {
"rollover-demo": {}
}
}'
{
"acknowledged" : true,
"shards_acknowledged" : true,
"old_index" : "rollover-demo-000001",
"new_index" : "rollover-demo-000002",
"rolled_over" : true,
"dry_run" : false,
"lazy" : false,
"conditions" : {
"[max_docs: 1]" : true
}
}
Rolling over only the write alias does not keep one-name searches across historical generations. Keep a separate read alias such as rollover-demo, or query an explicit pattern, when older indices must remain searchable after the write target advances.
$ curl -sS --fail "http://localhost:9200/_cat/aliases/rollover-demo*?v&s=alias,index" alias index filter routing.index routing.search is_write_index rollover-demo rollover-demo-000001 - - - - rollover-demo rollover-demo-000002 - - - - rollover-demo-write rollover-demo-000001 - - - false rollover-demo-write rollover-demo-000002 - - - true
The read alias spans both generations, while the write alias now targets only rollover-demo-000002. The _cat APIs are intended for human-readable inspection; use the JSON alias APIs for automation or programmatic checks.
$ curl -sS --fail -H "Content-Type: application/json" -X POST "http://localhost:9200/rollover-demo-write/_doc?refresh=wait_for&pretty&filter_path=_index,_id,result" -d '{
"@timestamp": "2026-04-02T07:21:00Z",
"message": "post-rollover event"
}'
{
"_index" : "rollover-demo-000002",
"_id" : "Lc4BTZ0BJgxRBVGyzhEp",
"result" : "created"
}
The response _index field confirms that new writes land in the latest rollover generation.
$ curl -sS --fail "http://localhost:9200/rollover-demo/_search?pretty&size=10&sort=%40timestamp:asc&filter_path=hits.total,hits.hits._index,hits.hits._source.message"
{
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"hits" : [
{
"_index" : "rollover-demo-000001",
"_source" : {
"message" : "pre-rollover event"
}
},
{
"_index" : "rollover-demo-000002",
"_source" : {
"message" : "post-rollover event"
}
}
]
}
}
Reading through rollover-demo returns both generations, which is why separate read and write aliases are useful for alias-based rollover.