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.
$ 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.
$ 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.
$ 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.
$ 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.
$ 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"
}
}
}
}
}
$ 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"
}
}
}
]
}
$ 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.
$ curl -sS --fail -X PUT "http://localhost:9200/app-logs-2026.05?pretty"
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "app-logs-2026.05"
}
$ 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"
}
}
}
}
$ curl -sS --fail "http://localhost:9200/_alias/app-logs-search?pretty"
{
"app-logs-2026.05" : {
"aliases" : {
"app-logs-search" : { }
}
}
}
$ 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.
$ 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
}
}
]
}
$ 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.
$ 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.