Index templates in Elasticsearch keep new indices consistent by applying the same shard layout, refresh settings, field mappings, and aliases whenever a matching index name is created. That reduces mapping drift, avoids repetitive JSON in create requests, and keeps application-owned index families predictable as they grow.

Modern Elasticsearch uses composable templates through the /_index_template API. Each template matches one or more index_patterns, can define settings, mappings, and aliases under template, and can optionally assemble reusable component templates through composed_of. When multiple index templates match the same new index or data stream, the template with the highest priority wins, while settings or mappings sent directly in a create-index request override the template result for that one index.

Templates affect only indices or data stream backing indices created after the template exists, so updates do not retrofit older indices automatically. Recent Elastic stacks also ship built-in templates for patterns such as logs-*-* and metrics-*-*, so custom templates should usually use an application-specific pattern instead of a broad shared prefix. Secured clusters often require HTTPS, authentication,, and template creation or updates require a cluster privilege such as manage_index_templates.

Steps to create and manage index templates in Elasticsearch:

  1. Create an index template for a specific application log pattern.
    $ curl -sS --fail -H "Content-Type: application/json" -X PUT "http://localhost:9200/_index_template/app-logs-template?pretty" -d '{
      "index_patterns": ["app-logs-*"],
      "priority": 300,
      "version": 1,
      "_meta": {
        "description": "Defaults for application log indices"
      },
      "template": {
        "settings": {
          "number_of_shards": 1,
          "number_of_replicas": 0,
          "refresh_interval": "30s"
        },
        "mappings": {
          "properties": {
            "timestamp": { "type": "date" },
            "level": { "type": "keyword" },
            "message": { "type": "text" }
          }
        }
      }
    }'
    {
      "acknowledged" : true
    }

    An application-specific pattern such as app-logs-* avoids unintentional overlap with built-in templates. If a custom template must intentionally override built-ins or Fleet-managed templates, current Elastic guidance is to use a priority above 500.

  2. Simulate template resolution for a matching index name before creating the index.
    $ curl -sS --fail -X POST "http://localhost:9200/_index_template/_simulate_index/app-logs-2026.04?pretty&filter_path=template.settings.index.number_of_shards,template.settings.index.number_of_replicas,template.settings.index.refresh_interval,template.mappings.properties,overlapping"
    {
      "template" : {
        "settings" : {
          "index" : {
            "refresh_interval" : "30s",
            "number_of_shards" : "1",
            "number_of_replicas" : "0"
          }
        },
        "mappings" : {
          "properties" : {
            "level" : {
              "type" : "keyword"
            },
            "message" : {
              "type" : "text"
            },
            "timestamp" : {
              "type" : "date"
            }
          }
        }
      },
      "overlapping" : [ ]
    }

    Simulation shows the resolved template without creating an index. Remove filter_path when the full overlap and merge details are needed for troubleshooting.

  3. Create a test index that matches the template pattern.
    $ curl -sS --fail -X PUT "http://localhost:9200/app-logs-2026.04?pretty"
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "app-logs-2026.04"
    }

    Index templates are applied only when the index is created, so creating a test index is the practical proof that the resolved template works.

  4. Verify the inherited shard, replica, and refresh settings on the new index.
    $ curl -sS --fail "http://localhost:9200/app-logs-2026.04/_settings?pretty&filter_path=*.settings.index.number_of_shards,*.settings.index.number_of_replicas,*.settings.index.refresh_interval"
    {
      "app-logs-2026.04" : {
        "settings" : {
          "index" : {
            "refresh_interval" : "30s",
            "number_of_shards" : "1",
            "number_of_replicas" : "0"
          }
        }
      }
    }

    Using number_of_replicas 0 keeps a one-node validation cluster green. Raise the replica count on multi-node clusters.

  5. Verify the inherited field mappings on the new index.
    $ curl -sS --fail "http://localhost:9200/app-logs-2026.04/_mapping?pretty&filter_path=*.mappings.properties"
    {
      "app-logs-2026.04" : {
        "mappings" : {
          "properties" : {
            "level" : {
              "type" : "keyword"
            },
            "message" : {
              "type" : "text"
            },
            "timestamp" : {
              "type" : "date"
            }
          }
        }
      }
    }
  6. Retrieve the stored template definition for review.
    $ curl -sS --fail "http://localhost:9200/_index_template/app-logs-template?pretty&filter_path=index_templates.name,index_templates.index_template.index_patterns,index_templates.index_template.priority,index_templates.index_template.version,index_templates.index_template._meta,index_templates.index_template.template.settings.index.number_of_shards,index_templates.index_template.template.settings.index.number_of_replicas,index_templates.index_template.template.settings.index.refresh_interval"
    {
      "index_templates" : [
        {
          "name" : "app-logs-template",
          "index_template" : {
            "index_patterns" : [
              "app-logs-*"
            ],
            "template" : {
              "settings" : {
                "index" : {
                  "number_of_shards" : "1",
                  "number_of_replicas" : "0",
                  "refresh_interval" : "30s"
                }
              }
            },
            "priority" : 300,
            "version" : 1,
            "_meta" : {
              "description" : "Defaults for application log indices"
            }
          }
        }
      ]
    }
  7. Update the template by resubmitting it with a higher version and additional defaults.
    $ curl -sS --fail -H "Content-Type: application/json" -X PUT "http://localhost:9200/_index_template/app-logs-template?pretty" -d '{
      "index_patterns": ["app-logs-*"],
      "priority": 300,
      "version": 2,
      "_meta": {
        "description": "Defaults for application log indices"
      },
      "template": {
        "settings": {
          "number_of_shards": 1,
          "number_of_replicas": 0,
          "refresh_interval": "5s"
        },
        "mappings": {
          "properties": {
            "timestamp": { "type": "date" },
            "level": { "type": "keyword" },
            "message": { "type": "text" },
            "service": {
              "properties": {
                "name": { "type": "keyword" }
              }
            }
          }
        },
        "aliases": {
          "app-logs-search": {}
        }
      }
    }'
    {
      "acknowledged" : true
    }

    Updating an index template changes only future indices that match the pattern. Existing indices keep the settings, mappings, and aliases they already received at creation time.

  8. Create a new matching index after the update.
    $ curl -sS --fail -X PUT "http://localhost:9200/app-logs-2026.05?pretty"
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "app-logs-2026.05"
    }
  9. Verify the updated refresh interval on the newly created index.
    $ curl -sS --fail "http://localhost:9200/app-logs-2026.05/_settings?pretty&filter_path=*.settings.index.refresh_interval,*.settings.index.number_of_replicas"
    {
      "app-logs-2026.05" : {
        "settings" : {
          "index" : {
            "refresh_interval" : "5s",
            "number_of_replicas" : "0"
          }
        }
      }
    }
  10. Verify the new alias on the newly created index.
    $ curl -sS --fail "http://localhost:9200/_alias/app-logs-search?pretty"
    {
      "app-logs-2026.05" : {
        "aliases" : {
          "app-logs-search" : { }
        }
      }
    }
  11. Verify the new field mapping on the newly created index.
    $ curl -sS --fail "http://localhost:9200/app-logs-2026.05/_mapping?pretty&filter_path=*.mappings.properties.service.properties.name"
    {
      "app-logs-2026.05" : {
        "mappings" : {
          "properties" : {
            "service" : {
              "properties" : {
                "name" : {
                  "type" : "keyword"
                }
              }
            }
          }
        }
      }
    }

    The original app-logs-2026.04 index keeps the older 30s refresh interval and does not gain the new alias or service.name mapping retroactively.

  12. List matching templates to confirm the stored version.
    $ curl -sS --fail "http://localhost:9200/_index_template/app-logs-*?pretty&filter_path=index_templates.name,index_templates.index_template.version"
    {
      "index_templates" : [
        {
          "name" : "app-logs-template",
          "index_template" : {
            "version" : 2
          }
        }
      ]
    }
  13. Delete the example indices after validation is complete.
    $ curl -sS --fail -X DELETE "http://localhost:9200/app-logs-2026.04?pretty"
    {
      "acknowledged" : true
    }
    
    $ curl -sS --fail -X DELETE "http://localhost:9200/app-logs-2026.05?pretty"
    {
      "acknowledged" : true
    }

    Deleting either index permanently removes the documents already stored in it.

  14. Delete the example template after validation is complete.
    $ curl -sS --fail -X DELETE "http://localhost:9200/_index_template/app-logs-template?pretty"
    {
      "acknowledged" : true
    }

    Deleting the template stops its defaults from applying to future indices.