Keeping time-series data under control in Elasticsearch is easier when rollover and retention happen automatically instead of through manual index housekeeping.
The Index Lifecycle Management (ILM) engine evaluates a policy made of phases (such as hot and delete) and runs the configured actions when an index reaches the defined age/size thresholds. For classic index patterns, rollover is driven by an alias that points to the current write index, while the policy is attached through index settings or a composable index template.
A policy only affects indices that have index.lifecycle.name set, and rollover only works when index.lifecycle.rollover_alias exists as an alias with a write index. Clusters with security enabled require authentication for these API calls, and rollover/delete actions happen asynchronously based on the ILM poll interval rather than instantly.
Steps to create an index lifecycle policy in Elasticsearch:
- Create the ILM policy defining rollover at 7 days or 50 GB, delete at 30 days.
$ curl --silent -H "Content-Type: application/json" --request PUT "http://localhost:9200/_ilm/policy/logs-policy?pretty" --data '{ "policy": { "phases": { "hot": { "actions": { "rollover": { "max_age": "7d", "max_size": "50gb" } } }, "delete": { "min_age": "30d", "actions": { "delete": {} } } } } }' { "acknowledged" : true }Secure clusters require authentication, so add a suitable Authorization header or a -u user:pass option.
- Confirm the policy is stored with the expected phase actions.
$ curl --silent "http://localhost:9200/_ilm/policy/logs-policy?pretty" { "logs-policy" : { "version" : 1, "modified_date" : "2026-01-06T14:40:50.545Z", "policy" : { "phases" : { "hot" : { "min_age" : "0ms", "actions" : { "rollover" : { "max_age" : "7d", "max_size" : "50gb" } } }, "delete" : { "min_age" : "30d", "actions" : { "delete" : { "delete_searchable_snapshot" : true } } } } }, "in_use_by" : { "indices" : [ ], "data_streams" : [ ], "composable_templates" : [ ] } } } - Create a composable index template that applies logs-policy, setting logs-write as the rollover alias for logs-* indices.
$ curl --silent -H "Content-Type: application/json" --request PUT "http://localhost:9200/_index_template/logs-ilm?pretty" --data '{ "index_patterns": ["logs-*"], "priority": 300, "template": { "settings": { "index.lifecycle.name": "logs-policy", "index.lifecycle.rollover_alias": "logs-write" } } }' { "acknowledged" : true }Rollover fails if logs-write is not an alias or if it does not point to a write index.
- Simulate template resolution for an index name matching the pattern to verify the ILM settings are included.
$ curl --silent --request POST "http://localhost:9200/_index_template/_simulate_index/logs-000001?pretty" { "template" : { "settings" : { "index" : { "lifecycle" : { "name" : "logs-policy", "rollover_alias" : "logs-write" }, "routing" : { "allocation" : { "include" : { "_tier_preference" : "data_content" } } } } }, "aliases" : { } }, "overlapping" : [ { "name" : "logs", "index_patterns" : [ "logs-*-*" ] }, { "name" : "logs-template", "index_patterns" : [ "logs-*" ] } ] } - Bootstrap the initial write index with logs-write configured as the write alias.
$ curl --silent -H "Content-Type: application/json" --request PUT "http://localhost:9200/logs-000001?pretty" --data '{ "aliases": { "logs-write": { "is_write_index": true } } }' { "acknowledged" : true, "shards_acknowledged" : true, "index" : "logs-000001" }Keep the index name in a rollover-friendly sequence (for example logs-000001, logs-000002) so the rollover action can generate the next index name.
- Verify the rollover alias points to the expected write index.
$ curl --silent "http://localhost:9200/_cat/aliases/logs-write?h=alias,index,is_write_index&v" alias index is_write_index logs-write logs-000001 true
- Check the lifecycle state to confirm ILM is managing the index.
$ curl --silent "http://localhost:9200/logs-000001/_ilm/explain?pretty" { "indices" : { "logs-000001" : { "index" : "logs-000001", "managed" : true, "policy" : "logs-policy", "index_creation_date_millis" : 1767710472934, "time_since_index_creation" : "7.63s", "lifecycle_date_millis" : 1767710472934, "age" : "7.63s", "phase" : "new", "phase_time_millis" : 1767710472837, "action" : "complete", "action_time_millis" : 1767710472837, "step" : "complete", "step_time_millis" : 1767710472837, "phase_execution" : { "policy" : "logs-policy", "version" : 1, "modified_date_in_millis" : 1767710450545 } } } }
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
