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.

Steps to perform an index rollover in Elasticsearch:

  1. Create the initial index with a dedicated write alias, a separate read alias, and single-node replica settings.
    $ 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.

  2. Index a test document through the write alias.
    $ 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.

  3. Preview the rollover conditions without creating the next index yet.
    $ 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.

  4. Run the rollover request against the write alias.
    $ 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.

  5. Inspect the alias assignments after rollover.
    $ 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.

  6. Index another test document through the write alias.
    $ 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.

  7. Search through the read alias to confirm both generations remain queryable.
    $ 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.