What it is
yq is a portable command-line YAML processor that works like jq but for YAML, allowing you to query, modify, and convert YAML files.
Installation
Linux
# Using snap (recommended)
sudo snap install yq
# Using Homebrew (if you have it installed)
brew install yq
# Download binary (check releases page for latest version)
wget https://github.com/mikefarah/yq/releases/download/v4.30.5/yq_linux_amd64
chmod +x yq_linux_amd64
sudo mv yq_linux_amd64 /usr/local/bin/yq
macOS
# Using Homebrew (recommended)
brew install yq
Windows
# Using Chocolatey
choco install yq
# Using Scoop
scoop install yq
# Download binary (check releases page for latest version)
# Navigate to the downloaded directory in PowerShell
Invoke-WebRequest -Uri https://github.com/mikefarah/yq/releases/download/v4.30.5/yq_windows_amd64.exe -OutFile yq.exe
# Move to PATH
Move-Item .\yq.exe "$env:ProgramFiles\yq.exe"
Core Concepts
- YAML Path Expressions: Similar to
jq’s JSON paths,yquses path expressions to navigate and select elements within a YAML document. These paths can be simple keys, array indices, or more complex selectors. - In-place Editing:
yqcan modify files directly using the-iflag. - Multiple Documents: YAML files can contain multiple documents separated by
---.yqcan operate on all documents or specific ones. - Data Types:
yqpreserves YAML data types (strings, numbers, booleans, nulls, arrays, maps) and handles their conversion when necessary.
Commands / Usage
Reading and Querying YAML
-
Print the entire YAML document:
yq '.' config.yamlPrints the whole
config.yamlfile. -
Select a top-level key:
yq '.database.port' config.yamlPrints the value of the
portkey underdatabase. -
Select a nested key:
yq '.users[0].name' users.yamlPrints the
nameof the first user in theusersarray. -
Select from an array:
yq '.servers[1]' servers.yamlPrints the second server object from the
serversarray. -
Select all elements of an array:
yq '.servers[].ip' servers.yamlPrints the
ipaddress of each server in theserversarray. -
Select keys from array elements:
yq '.users.[].address.city' users.yamlPrints the city from the address of each user.
-
Select multiple fields:
yq '.name, .version' package.yamlPrints the values of
nameandversionas a YAML array. -
Select a map of fields:
yq '{name: .name, version: .version}' package.yamlPrints a new YAML object containing
nameandversion. -
Filter array elements:
yq '.users[] | select(.age > 30)' users.yamlPrints users whose
ageis greater than 30. -
Accessing values in a map where keys have special characters:
yq '."special-key"' config.yamlAccesses a key named "special-key".
-
Accessing keys that are numbers (as strings):
yq '.["123"].value' data.yamlAccesses the value associated with the key "123".
Modifying YAML
-
Update a value:
yq '.database.port = 5433' config.yamlPrints the
config.yamlwith the database port changed to5433. -
Update a nested value:
yq '.users[0].active = false' users.yamlPrints the
users.yamlwith the first user’sactivestatus set tofalse. -
Add a new key-value pair:
yq '.database.user = "admin"' config.yamlPrints
config.yamlwith a newuserkey and value added todatabase. -
Add an element to an array:
yq '.servers += {"ip": "192.168.1.100", "role": "backup"}' servers.yamlAppends a new server object to the
serversarray. -
Insert an element at a specific index:
yq '.servers[1] = {"ip": "192.168.1.50", "role": "staging"}' servers.yamlReplaces the element at index 1 with a new server object.
-
Delete a key:
yq 'del(.database.password)' config.yamlPrints
config.yamlwith thepasswordkey removed fromdatabase. -
Delete an array element by index:
yq 'del(.servers[0])' servers.yamlPrints
servers.yamlwith the first server removed. -
Delete array elements by condition:
yq 'del(.users[] | select(.age < 18))' users.yamlPrints
users.yamlwith all users younger than 18 removed.
Converting Formats
-
Convert YAML to JSON:
yq -o json '.' config.yamlPrints the
config.yamlcontent as JSON. -
Convert JSON to YAML:
yq -p json '.' config.jsonPrints the
config.jsoncontent as YAML. -
Convert TOML to YAML:
yq -p toml '.' config.tomlPrints the
config.tomlcontent as YAML.
Working with Multiple Documents
-
Select a specific document (0-indexed):
yq --doc 1 '.key' multi_doc.yamlPrints the value of
keyfrom the second document inmulti_doc.yaml. -
Operate on all documents:
yq --doc '*' '.key |= . + "_suffix"' multi_doc.yamlAppends
_suffixto the value ofkeyin all documents. -
Merge multiple YAML files:
yq eval-all --inplace '. as $item ireduce ({}; . * $item)' file1.yaml file2.yaml file3.yamlMerges
file1.yaml,file2.yaml, andfile3.yamlintofile1.yaml, with later files overwriting earlier ones.
In-place Editing
-
Modify a file directly:
yq -i '.database.port = 5433' config.yamlUpdates
config.yamlin place with the new database port. -
Modify multiple files in place:
yq -i '.version = "1.1.0"' *.yamlUpdates the
versionkey in all.yamlfiles in the current directory.
Advanced Operations
-
Create a new YAML structure:
yq -n '{name: "example", version: "1.0.0"}'Creates a new YAML structure.
-
Concatenate strings:
yq '.message = (.greeting + " " + .name)' data.yamlConcatenates
greetingandnamefields into a newmessagefield. -
Iterate and transform:
yq '.users[] |= .name = (.name | ascii_upcase)' users.yamlConverts all user names to uppercase.
-
Conditional assignment:
yq '.users[] |= if .age > 18 then .status = "adult" else .status = "minor" end' users.yamlAssigns a
statusbased onage. -
Using variables:
NEW_PORT=5433 yq '.database.port = env(NEW_PORT)' config.yamlSets the database port using an environment variable.
-
Read from stdin, write to stdout:
cat config.yaml | yq '.database.host'Pipes the content of
config.yamltoyqto extract the database host. -
Read from stdin, modify, write to stdout:
cat config.yaml | yq '.database.port |= . + 1'Increments the database port read from stdin.
-
Read from stdin, modify in place (requires a temp file or careful piping):
# Example: update a value and save back to the original file yq -i '.database.port = 5433' config.yaml(Note: Direct in-place modification from stdin to a file isn’t a standard
yqoperation without redirection. The-iflag operates on the specified file path.)
Common Patterns
-
Extracting a specific value from multiple files:
yq '.version' file1.yaml file2.yaml file3.yamlPrints the
versionfrom each file, outputting them sequentially. -
Updating a common value across multiple files:
yq -i '.environment = "production"' *.yamlSets the
environmenttoproductionin all YAML files in the current directory. -
Converting a YAML file to JSON and saving:
yq -o json '.' config.yaml > config.jsonConverts
config.yamlto JSON and saves it toconfig.json. -
Merging two YAML files with precedence:
yq eval '. as $item ireduce ({}; . * $item)' base.yaml overrides.yamlMerges
overrides.yamlintobase.yaml, with values fromoverrides.yamltaking precedence. -
Creating a new YAML file from scratch:
yq -n '{ apiVersion: "v1", kind: "Pod", metadata: {name: "my-pod"}, spec: {containers: [{name: "nginx", image: "nginx:latest"}]} }' > pod.yamlCreates a
pod.yamlfile with the specified content. -
Extracting data and formatting as a string:
yq -r '.users[] | "\(.name) is \(.age) years old"' users.yamlOutputs a human-readable string for each user. The
-rflag outputs raw strings, not YAML. -
Iterating over maps and modifying values:
yq '.config.settings |= with_entries(if .key | test("timeout") then .value |= . * 1000 else . end)' config.yamlMultiplies any setting value whose key contains "timeout" by 1000.
Gotchas
- YAML vs JSON Syntax: While
yqcan process JSON, remember that YAML has nuances like implicit typing, anchors, and aliases thatjqdoesn’t handle.yqaims to respect these YAML features. - In-place Editing (
-i): Be cautious with-i. It modifies the file directly. Always have backups or use version control when performing extensive in-place modifications. - Multiple Documents: When operating on files with multiple YAML documents, be mindful of which document you are targeting with
--doc. If omitted, operations might apply to the first document or behave unexpectedly depending on the command.eval-allis often safer for multi-document operations. - Path Expression Syntax: While similar to
jq,yq’s path expressions can have subtle differences, especially when dealing with complex YAML structures or specific operators. Always test your expressions. - Operator Precedence: Complex expressions involving multiple operators might require careful consideration of precedence or the use of parentheses for clarity.
evalvseval-all:evalprocesses the input as a single YAML document (or the first document if multiple exist).eval-allprocesses all YAML documents within the input. Useeval-allwhen you need to apply an operation consistently across all documents in a file.- Quoting: Shell expansion can interfere with
yq’s path expressions. Always quote youryqexpressions to prevent the shell from interpreting special characters. For example, useyq '.users[0].name'instead ofyq .users[0].name. - Empty Values: Be aware of how
yqhandles null values or empty strings, especially during updates or comparisons.