Skip to content
Latchkey

yq: Merge YAML with the * Operator

In yq, the * operator merges two maps, recursively combining their keys; later values override earlier ones.

Config overlays are everywhere in CI: a base file plus an environment-specific override. yq spells deep merge as multiplication, with modifiers that change how arrays and nulls behave.

What it does

The * operator deep-merges two maps. By default, scalar values on the right replace those on the left and arrays are replaced (not concatenated). Modifiers tune this: *+ appends arrays, *? only sets keys that do not already exist, *d deep-merges and deletes.

Common usage

Terminal
# merge overlay.yaml onto base.yaml
yq '. *= load("overlay.yaml")' base.yaml
# append arrays instead of replacing them
yq '. *+= load("overlay.yaml")' base.yaml
# only fill in keys that are missing
yq '. *?= load("defaults.yaml")' values.yaml

Merge modifiers

OperatorBehavior
*Deep-merge; right wins, arrays replaced
*+Deep-merge; arrays concatenated
*?Only set keys not already present
*nMerge but keep nulls from the right out
*=Update-assign form of any of the above
load("f.yaml")Load another file as a value to merge

In CI

A base values.yaml plus an environment overlay merges cleanly with yq -i '. *= load("prod-overrides.yaml")' values.yaml. Remember arrays are replaced by default; if you want to add a sidecar container rather than overwrite the list, use *+.

Common errors in CI

Expecting arrays to combine but seeing the base list vanish means you used * (replace) instead of *+ (append). "Error: cannot load file ..." from load() means a wrong path relative to the runner working directory. Merging requires the values in scope, so prefer load() inside eval, or use eval-all for file-to-file merges; mixing the two patterns is a frequent mistake.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →