Pulse 2025 Product Roundup: From Monitoring to AI-Native Control Plane

Read more

Elasticsearch Composable Index Templates

Elasticsearch introduced composable index templates in version 7.8, replacing the legacy template system. The old _template API still works in 7.x but is fully deprecated and removed in 8.x. Composable templates use the _index_template API and bring a modular design that allows sharing configuration across multiple templates through component templates.

The core improvement over legacy templates is deterministic resolution. Legacy templates used an order field and allowed multiple templates to match a single index, merging their configurations together. Composable templates enforce strict rules: only one template can match, determined by a priority value. This eliminates ambiguity and makes it clear which configuration applies to any given index.

Component Templates as Building Blocks

Component templates are reusable configuration fragments that define mappings, settings, or aliases. They have no index patterns of their own and cannot match indices directly. Their purpose is to be composed into one or more index templates via the composed_of array.

Create a component template with the _component_template API:

PUT _component_template/my-mappings
{
  "template": {
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "message": { "type": "text" }
      }
    }
  }
}

PUT _component_template/my-settings
{
  "template": {
    "settings": {
      "number_of_replicas": 1,
      "refresh_interval": "10s"
    }
  }
}

These components become useful when referenced from an index template. A single component template can be shared across dozens of index templates, so updating one component propagates changes everywhere it is referenced. This is particularly useful for organizations that standardize on specific analyzer configurations, shard settings, or ILM policies across many index patterns.

The _index_template API and Priority

Composable index templates are managed through the _index_template API. Each template must define index_patterns and should specify a priority (defaults to 0 if omitted). The composed_of array lists component templates to include.

PUT _index_template/my-template
{
  "index_patterns": ["logs-*"],
  "priority": 200,
  "composed_of": ["my-mappings", "my-settings"],
  "template": {
    "settings": {
      "number_of_shards": 2
    }
  }
}

When an index is created, Elasticsearch finds all composable templates whose patterns match the index name. If multiple templates match, the one with the highest priority wins. Two composable templates with overlapping patterns and the same priority are not allowed - Elasticsearch will reject the second template at creation time with an error stating that multiple index templates may not match during index creation. This is a deliberate constraint that prevents the ambiguous merging behavior of legacy templates.

Composable templates always take precedence over legacy templates. If both a composable and a legacy template match an index name, the composable template wins regardless of the legacy template's order value.

How Mappings and Settings Merge

Within a single composable template, configuration is assembled from multiple sources in a specific order. Component templates listed in composed_of are applied left to right. If two component templates define the same setting or mapping field, the later component in the array wins. Settings and mappings defined directly in the index template's template block are applied last and override everything from the components.

For example, if composed_of: ["base-settings", "override-settings"] and both define number_of_replicas, the value from override-settings is used. If the index template itself also defines number_of_replicas in its template.settings block, that value takes final precedence.

Mapping merges follow the same principle but operate at the field level. Two components can each contribute different fields without conflict. When they define the same field name with different types or parameters, the later component's definition wins. Deep merging applies to nested objects - properties from both components are combined, but conflicting leaf properties resolve in favor of the later source.

Template Simulation

Before applying a template to production, use the simulation APIs to verify the final merged result. Elasticsearch provides two endpoints for this.

POST _index_template/_simulate/<template-name> shows the resolved configuration that would result from an existing named template, including all component template contributions merged together. This helps verify that a template you have already registered produces the expected output.

POST _index_template/_simulate/my-template

POST _index_template/_simulate_index/<index-name> takes an index name and returns the full configuration that would be applied if that index were created right now. This is useful for debugging which template matches a given index pattern and what the resulting mappings, settings, and aliases look like.

POST _index_template/_simulate_index/logs-2026.03.04

You can also POST a template body to _index_template/_simulate without saving it to the cluster. This lets you test a template configuration in a request body before committing it. The response includes the resolved template and lists any overlapping templates whose configuration would be superseded.

Common Errors and Data Stream Templates

The most frequent error is attempting to create a template with index patterns that overlap an existing template at the same priority. Elasticsearch rejects this with a message indicating that the patterns conflict with an existing template. The fix is to assign a different priority or adjust the patterns to avoid overlap. For templates that need to coexist with built-in Elastic templates (like those for Fleet or Elastic Agent), assign a priority above 500.

The index_template_already_exists_exception occurs when you try to create a template with a name that already exists without explicitly replacing it. Use a PUT request to the same name to update an existing template.

If a component template referenced in composed_of does not exist, the index template creation fails immediately. All component templates must exist before they can be referenced. Deleting a component template that is still referenced by an active index template is also blocked.

For data stream usage, the index template must include a data_stream object in the body. Even an empty data_stream: {} is sufficient. Without this object, indices created from the template are regular indices rather than backing indices of a data stream. The template must also include a mapping for @timestamp as a date or date_nanos type, either directly or through a component template.

PUT _index_template/my-data-stream-template
{
  "index_patterns": ["metrics-*"],
  "data_stream": {},
  "priority": 300,
  "composed_of": ["my-mappings", "my-settings"]
}

Forgetting the data_stream object is a common mistake when migrating from regular indices to data streams. The error message at index creation time will indicate that the index name matches a data stream pattern but no matching template with a data_stream definition was found.

Pulse - Elasticsearch Operations Done Right

Pulse can solve your Elasticsearch issues

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.