How to Use yq to Read, Update, and Merge YAML Files

Updated

yq is a command-line processor that uses jq-like syntax to read and modify YAML, JSON, XML, INI, properties, CSV, and TSV files. To read a value, run yq '.a.b[0].c' file.yaml; to update a file in place, add the -i flag; to merge files, use load() with * or combine ea with ireduce. The examples below assume yq v4.x and a file named file.yaml containing nested keys, arrays, and comments.

Read a value from a file

Pass an expression and a filename. The expression is a path into the document, and yq prints the matching value.

yq '.a.b[0].c' file.yaml
  • Input: file.yaml with a structure like a: {b: [{c: ...}]}.
  • Action: yq evaluates the path expression.
  • Expected result: the value at .a.b[0].c is printed to stdout. The file is not changed.

You can also pipe the document in through STDIN instead of naming a file:

yq '.a.b[0].c' < file.yaml

This is useful when another command produces the YAML. The expression and output behavior are the same.

Update a YAML file in place

Add -i to write the result back to the same file. Without -i, yq prints the modified document to stdout and leaves the file untouched.

yq -i '.a.b[0].c = "cool"' file.yaml
  • Input: the existing file.yaml.
  • Action: the assignment sets .a.b[0].c to the string cool, and -i overwrites the file.
  • Expected result: file.yaml now contains the new value; other content is preserved as far as yq can preserve it.

To update from an environment variable, use strenv() so the value is read as a string:

NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
  • Input: the environment variable NAME set to mike.
  • Action: strenv(NAME) resolves to the variable's value at evaluation time.
  • Expected result: .a.b[0].c becomes mike in the file.

This pattern is handy in scripts and CI, where values come from the environment rather than being hard-coded.

To find and update an item inside an array, select the element first and then assign. The documentation points to recipes and the full docs for concrete array examples; the general shape is a select/path expression followed by = value, run with -i to persist the change.

Merge multiple files

There are two documented approaches, and they behave differently.

Merge two named files with load() and *

yq -n 'load("file1.yaml") * load("file2.yaml")'
  • Input: two files, loaded explicitly by name.
  • Action: -n means "no input file"; the expression loads both documents and * merges them.
  • Expected result: the merged document is printed to stdout.

Merge many files with a glob, ea, and ireduce

yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
  • Input: every .yml file matching the glob.
  • Action: ea evaluates all files at once instead of in sequence; ireduce folds them one by one into an accumulator starting from {}, merging each with *.
  • Expected result: a single merged document printed to stdout.

The ea flag matters here: the docs note it evaluates all files at once rather than in sequence, which is what makes the reduce over the whole set work as intended.

Things to watch for

  • Comments and whitespace: yq tries to preserve comment positions and whitespace, but it does not handle every scenario. If formatting matters, check the output before committing.
  • PowerShell quoting: PowerShell has its own quoting rules that can interfere with yq expressions. The docs point to tips and tricks for common problems and solutions.
  • Coverage vs. jq: yq uses jq-like syntax but does not support everything jq does. The most common operations and functions are supported, and more are added over time.
  • Installation: yq is written in Go, so you can download a dependency-free binary for your platform, or install via package managers, Docker, or Podman. The GitHub page lists the available methods.

For more examples, see the recipes and the full documentation; the discussions cover common questions.