skip to content

In what order does Elasticsearch merge composed_of component templates into an index's configuration?

level: middleimportance: should knowfreq 52%

answer

  1. order in the list is meaningful
  2. later entries beat earlier ones
  3. the template's own block sits on top
  4. the create-index request outranks everything

basics

~20 s

Component templates named in composed_of are merged in array order, each overriding the previous one on conflicts. The index template's own template block is applied last and beats them all, and anything supplied in the create-index request overrides even that.

solid answer

~50 s

Precedence runs left to right and then outward. Elasticsearch merges the component templates in the exact order they appear in `composed_of`, so the **last** entry has the highest precedence among components. On top of that it applies the index template's own `template` block, which overrides any component. Finally, `settings` and `mappings` supplied directly in the create-index request override everything. Merging is per key, not whole-block replacement: settings merge key by key, aliases merge by alias name, and mappings merge field by field with object properties combining recursively, so one component can contribute `@timestamp` while another contributes `user.id`. Two operational details matter. A component template does nothing on its own — it only takes effect through some index template's `composed_of` — and Elasticsearch refuses to delete a component template that an index template still references, which is a useful safety net but means teardown has an order too.

code

bash · 15 lines
bash
PUT _component_template/base-settings
{ "template": { "settings": { "number_of_shards": 1, "number_of_replicas": 1 } } }

PUT _component_template/common-fields
{ "template": { "mappings": { "properties": {
    "@timestamp": { "type": "date" },
    "service.name": { "type": "keyword" } } } } }

PUT _index_template/orders
{
  "index_patterns": ["orders-*"],
  "priority": 200,
  "composed_of": ["base-settings", "common-fields"],
  "template": { "settings": { "number_of_shards": 6 } }
}

go deeper

for a junior

Know that composed_of pulls in reusable component templates and that order matters. You are not expected to recite the full precedence chain at this level.

for a middle

State the chain precisely - components in array order, then the template's own block, then the create-index request - and explain that merging is per setting and per field, not block replacement.

for a senior

Talk about verification and safety: simulate the composed result in CI, treat composed_of reordering as a real diff, and know the delete-protection ordering when tearing configuration down.

for a principal

Decide the layering itself. Choose how many semantic component layers a platform gets and who may edit which, so that any setting's origin is answerable without archaeology across a deep chain.

## Why composition exists Before composable templates, sharing configuration between index families meant copying JSON. Component templates fix that: you store reusable fragments once (`PUT _component_template/base-settings`, `PUT _component_template/common-fields`) and index templates assemble them with `composed_of: ["base-settings", "common-fields"]`. The fragments have exactly the same shape as an index template's `template` block — `settings`, `mappings`, `aliases` — but carry no `index_patterns` and no `priority`, because they never match anything themselves. ## The precedence chain For an index created under a winning index template, the effective configuration is built in this order, each layer overriding the ones before it: 1. every component template in `composed_of`, **in array order** — first entry lowest precedence, last entry highest; 2. the index template's own `template` block; 3. `settings`, `mappings` and `aliases` passed in the create-index request itself. So `composed_of: ["a", "b"]` means b wins over a, and the template's inline block wins over both. Reordering the array is a real configuration change, not cosmetics — a reviewer who treats `composed_of` as a set rather than a list will approve a broken diff. ## Merging is per key, not per block The layers do not replace one another wholesale. Merging happens at the finest granularity the structure allows: - **Settings** merge key by key. A component that sets only `index.number_of_replicas` leaves an earlier component's `index.refresh_interval` intact. - **Aliases** merge by alias name; two components can each contribute a different alias. - **Mappings** merge field by field. `properties` objects combine recursively, so a "common fields" component contributing `@timestamp` and `service.name` composes cleanly with a domain component contributing `order.total`. Where the *same* field path is defined twice, the higher-precedence layer's definition is the one that survives. The pieces people get wrong are the array-valued parts of a mapping — `dynamic_templates` most of all. Do not reason about those from first principles; compose the template and read the result from the simulate API, because a dynamic template that silently disappeared or silently doubled will only show up as strangely mapped fields much later. ## Component templates are inert on their own Storing a component template changes nothing about any index. It is a fragment sitting in the cluster state waiting to be referenced. This is a frequent support question: "I added the field to the component template and new indices still do not have it" — almost always because no index template's `composed_of` mentions it, or because the index template that *does* mention it lost the priority contest to another one. The inverse protection also exists: `DELETE _component_template/<name>` is rejected while any index template references that component. You must edit or delete the referring index templates first. That ordering constraint is worth knowing before you write a teardown script. From 8.7, `ignore_missing_component_templates` lets an index template list a component that does not exist yet without failing — the pattern Elastic's own integrations use to leave a hook for an optional user-supplied override component. ## A worked example Suppose `base` sets `number_of_shards: 1`, `regional` sets `number_of_shards: 3`, and the index template's inline block sets `number_of_shards: 5`, with `composed_of: ["base", "regional"]`. A new index gets **5** shards: `regional` beats `base` by position, the inline block beats both. If the operator then issues `PUT /orders-eu-1 {"settings": {"number_of_shards": 2}}`, the index gets 2, because the request body is the outermost layer. That last case is worth flagging in review. An explicit create-index body silently defeats the whole template stack, which is fine for a one-off experiment and terrible in automation, because the cluster now contains an index whose configuration cannot be explained by reading any template. ## How to design the layering Keep the layers semantic and few. A common working split is: one component for cluster-wide index settings, one for the shared field schema, one per team or domain for its own fields, and — highest precedence — a small override component reserved for emergencies. Deep chains of six or seven components make every question of the form "where does this setting come from?" into an archaeology exercise. Whatever the depth, the answer to that question always comes from the simulate API rather than from reading the JSON, because only the simulate output reflects the real merge.

  • What happens if you try to delete a component template that an index template references?
    Elasticsearch rejects the delete and names the index templates still referencing it. You must remove or edit those referring templates first. This prevents an index template from silently composing to less than its author intended, and it means teardown scripts need an explicit ordering.
  • Two component templates define the same field with different types. Is that an error?
    No. Composition is not a live mapping update, so the higher-precedence layer's definition simply replaces the lower one — quietly. That is why a field can appear with an unexpected type without anything failing, and why you verify the composed mapping with the simulate API rather than reading the fragments.
  • Why is reordering composed_of a substantive change rather than a cosmetic one?
    Because precedence is positional: the last component listed wins conflicts. Swapping two entries can flip a shard count, an analyzer or a field type. Treat composed_of as an ordered list in code review, and re-run a simulate assertion whenever it changes.

saying these in an interview costs you the question

  • Treats composed_of as an unordered set
  • Says the first component listed takes precedence
  • Thinks a component template applies to indices by itself
  • Expects a whole settings block to replace rather than merge per key
  • Forgets the create-index request body outranks the template

context