# Merge Keys
Merge keys (<<) let you combine mappings defined directly in a mapping with other mappings defined elsewhere, such as:
They promote reusability and avoid repetition by letting you define common mappings once and update them in a single place.
# What Merge Keys Do
A merge key takes one or more source mappings — whether written inline, referenced through an anchor, or loaded from another file — and merges their key–value pairs into the current mapping. The merged values behave exactly as if they were written inline, while still allowing local fields to add to or override the merged content.
# Merge Rules
- Only mappings can be merged.
- Merge keys may appear multiple times or as a list.
- Merge order matters: keys from earlier mappings override keys from later ones.
- Local keys always override merged keys, even when defined after a merge key.
- Merges are shallow: nested mappings are replaced, not combined.
# Example: Multiple Merges and Precedence
.defaults: &DEFAULTS
icon: default
autoupdate: false
.metadata: &LIGHTS
tags: [Light]
icon: light
items:
Lamp:
<<: [*LIGHTS, *DEFAULTS]
label: Desk Lamp
Result:
items:
Lamp:
label: Desk Lamp
icon: light # from LIGHTS (earlier mapping wins)
autoupdate: false
tags: [Light]
# Limitations
- Merge keys only merge mappings, not lists.
- Merge keys cannot modify scalar values.
- Merge keys cannot be used inside sequences unless the sequence elements are mappings.
# Integrating with Other Features
# Anchors
Anchors define reusable structures whose content can be inserted into the current mapping via an alias. Merge keys then combine that anchored content with any local fields in the mapping. While anchors are a standard YAML feature for sharing data within a single file, Variables or Templates are often preferred for more complex needs.
items:
Light1: &LIGHT_BASE
type: Switch
icon: light
autoupdate: false
label: Light One
Light2:
<<: *LIGHT_BASE
label: Light Two
See also: Using Hidden Keys for Anchors
# !include
The !include tag loads the contents of another file so it can be inserted into the current mapping. Merge keys then combine the included content with any local fields in the mapping.
Benefits over anchors:
- Included files can be parameterized, allowing the same structure to be reused with different values.
- Included files can be shared across many different YAML files, whereas anchors are limited to a single file.
# light-common.inc.yaml - all types of lights share this
power:
type: switch
stateTopic: !sub ${id}/power
availability:
type: contact
stateTopic: !sub ${id}/availability
# light-color.inc.yaml - only for RGB lights
color:
type: color
stateTopic: !sub ${id}/color
# main.yaml
things:
mqtt:topic:living-room-light:
channels:
<<: !include { file: light-common.inc.yaml, vars: { id: living-room-light } }
<<: !include { file: light-color.inc.yaml, vars: { id: living-room-light } }
# Templates (!insert)
The !insert tag inserts the contents of an in-file template into the current mapping. Merge keys then combine the template’s fields with any local fields in that mapping.
Benefits over anchors:
- Unlike anchors, templates can be parameterized when used through a merge key.
- Unlike
!include, templates are defined in the same file, making them easier to manage when the logic is specific to a single configuration.
templates:
common_channels:
power:
type: switch
stateTopic: !sub ${id}/power
availability:
type: contact
stateTopic: !sub ${id}/availability
color_channel:
color:
type: color
stateTopic: !sub ${id}/color
things:
mqtt:topic:living-room-light:
channels:
<<: !insert { template: common_channels, vars: { id: living-room-light } }
<<: !insert { template: color_channel, vars: { id: living-room-light } }
# Conditionals (!if)
The !if tag is the most powerful way to conditionally merge content.
Because the engine resolves tags before the merge, you can choose between different mappings or return null to skip the merge entirely.
# Merge extra settings only for production
server:
port: 8080
<<: !if
if: !sub ${is_prod}
value: { ssl: true, cache: true }
# Substitution (!sub)
Merge keys can also combine content produced dynamically by a !sub expression.
The key advantage is that !sub is type-aware: if a variable contains a map, !sub returns that map directly to the merge key.
This also allows for inline conditional merging using Python-style expressions:
variables:
has_color: true
color_channel:
color:
type: color
things:
mqtt:topic:light:
channels:
power:
type: switch
# Returns color_channel map if true
<<: !sub ${color_channel if has_color}
Hints:
- Merge keys only merge mappings, so
!submust resolve to a map. - Leave the pattern unquoted; quoting it causes
!subto return the value as a literal string. - Avoid compound patterns (
${foo}${bar},x${foo}, etc.). These are interpreted as literal strings and cannot be merged. - Merging
nullor an empty map is a no-op, effectively omitting the merge key. - If you use
!subinside an array for a merge key, make sure the array uses block style.
# Debugging Merge Behavior
Use Output & Debugging to inspect the fully resolved YAML.
The _generated output shows the fully resolved structure after merges, includes, substitutions, and packages.
See the Output & Debugging page for details on how to inspect the final YAML.
# Related Topics
For details on how variables are resolved and how substitution interacts with YAML structures, see Variables & Substitution — Interpolation and Inserted Content.
# Best Practices
- Use merge keys to define reusable base templates.
- Keep anchors inside hidden keys to avoid clutter.
- Use includes,
!include, or packages to centralize shared structures. - Use the
_generatedoutput to verify merge results. - Prefer simple, predictable structures for reusable blocks.