yq — Editing

In-Place Editing

yq’s -i flag writes changes directly to the file — the YAML equivalent of sed -i. Always verify before and after.

Update a scalar value in-place
cp docs/antora.yml /tmp/antora-test.yml
# Before
yq '.title' /tmp/antora-test.yml
# Output: Work Chronicles

yq -i '.title = "Test Title"' /tmp/antora-test.yml
# After
yq '.title' /tmp/antora-test.yml
# Output: Test Title
Verify-before/change/verify-after pattern (mandatory)
cp docs/antora.yml /tmp/antora-test.yml
# Before
yq '.asciidoc.attributes["current-month"]' /tmp/antora-test.yml
# Change
yq -i '.asciidoc.attributes["current-month"] = "May"' /tmp/antora-test.yml
# After
yq '.asciidoc.attributes["current-month"]' /tmp/antora-test.yml

Never use -i on the real docs/antora.yml without the verify pattern.

Adding Keys

Add a new top-level key
cat <<'YAML' > /tmp/test.yml
name: captures
version: ~
YAML
yq -i '.description = "Work Chronicles component"' /tmp/test.yml
yq '.' /tmp/test.yml
# Output:
# name: captures
# version: ~
# description: Work Chronicles component
Add a nested key (parent must exist)
cat <<'YAML' > /tmp/test.yml
asciidoc:
  attributes:
    domain: inside.domusdigitalis.dev
YAML
yq -i '.asciidoc.attributes["new-attr"] = "new-value"' /tmp/test.yml
yq '.asciidoc.attributes' /tmp/test.yml
# Output:
# domain: inside.domusdigitalis.dev
# new-attr: new-value
Add nested key — create parents automatically
cat <<'YAML' > /tmp/test.yml
name: test
YAML
yq -i '.deeply.nested.key = "works"' /tmp/test.yml
yq '.' /tmp/test.yml
# Output:
# name: test
# deeply:
#   nested:
#     key: works

yq creates intermediate parents automatically.

Deleting Keys

Delete a key
cat <<'YAML' > /tmp/test.yml
name: captures
title: Work Chronicles
deprecated: true
YAML
yq -i 'del(.deprecated)' /tmp/test.yml
yq '.' /tmp/test.yml
# Output:
# name: captures
# title: Work Chronicles
Delete multiple keys
cat <<'YAML' > /tmp/test.yml
a: 1
b: 2
c: 3
d: 4
YAML
yq -i 'del(.b, .d)' /tmp/test.yml
yq '.' /tmp/test.yml
# Output:
# a: 1
# c: 3
Delete keys matching a pattern
cat <<'YAML' > /tmp/test.yml
port-https: 443
port-ssh: 22
domain: example.com
port-dns: 53
YAML
yq -i 'del(.. | select(key | test("^port-")))' /tmp/test.yml 2>/dev/null
# Caution: recursive descent (`..`) can be tricky.
# Safer approach — use with_entries:
cat <<'YAML' > /tmp/test.yml
port-https: 443
port-ssh: 22
domain: example.com
port-dns: 53
YAML
yq -i 'with_entries(select(.key | test("^port-") | not))' /tmp/test.yml
yq '.' /tmp/test.yml
# Output:
# domain: example.com

Updating Values

Update with the |= operator
cat <<'YAML' > /tmp/test.yml
services:
  ise:
    port: 443
  vault:
    port: 8200
YAML
yq -i '.services.vault.port = 8201' /tmp/test.yml
yq '.services.vault.port' /tmp/test.yml
# Output: 8201
Conditional update — change value only if it matches
cat <<'YAML' > /tmp/hosts.yml
- name: ise-01
  status: active
- name: pfsense
  status: active
- name: vault-01
  status: standby
YAML
yq -i '(.[] | select(.name == "pfsense") | .status) = "deprecated"' /tmp/hosts.yml
yq '.' /tmp/hosts.yml
# Output:
# - name: ise-01
#   status: active
# - name: pfsense
#   status: deprecated
# - name: vault-01
#   status: standby

Merging Files

Merge two YAML files (second overrides first)
cat <<'YAML' > /tmp/base.yml
name: captures
version: "1.0"
features:
  search: true
  auth: false
YAML
cat <<'YAML' > /tmp/override.yml
version: "2.0"
features:
  auth: true
  logging: true
YAML
yq '. *= load("/tmp/override.yml")' /tmp/base.yml
# Output:
# name: captures
# version: "2.0"
# features:
#   search: true
#   auth: true
#   logging: true

*= is the merge-assign operator. It recursively merges maps. load() reads another file inline.

Append values from another file
cat <<'YAML' > /tmp/a.yml
hosts:
  - ise-01
  - vault-01
YAML
cat <<'YAML' > /tmp/b.yml
hosts:
  - vyos-01
  - dns-01
YAML
yq '.hosts += load("/tmp/b.yml").hosts' /tmp/a.yml
# Output:
# hosts:
#   - ise-01
#   - vault-01
#   - vyos-01
#   - dns-01

Array Manipulation

Append to an array
cat <<'YAML' > /tmp/test.yml
nav:
  - modules/ROOT/nav.adoc
YAML
yq -i '.nav += ["modules/ROOT/nav-extra.adoc"]' /tmp/test.yml
yq '.nav' /tmp/test.yml
# Output:
# - modules/ROOT/nav.adoc
# - modules/ROOT/nav-extra.adoc
Prepend to an array
cat <<'YAML' > /tmp/test.yml
hosts:
  - vault-01
  - dns-01
YAML
yq -i '.hosts = ["ise-01"] + .hosts' /tmp/test.yml
yq '.hosts' /tmp/test.yml
# Output:
# - ise-01
# - vault-01
# - dns-01
Delete array element by value
cat <<'YAML' > /tmp/test.yml
hosts:
  - ise-01
  - pfsense
  - vault-01
YAML
yq -i 'del(.hosts[] | select(. == "pfsense"))' /tmp/test.yml
yq '.hosts' /tmp/test.yml
# Output:
# - ise-01
# - vault-01
Delete array element by index
cat <<'YAML' > /tmp/test.yml
items:
  - first
  - second
  - third
YAML
yq -i 'del(.items[1])' /tmp/test.yml
yq '.items' /tmp/test.yml
# Output:
# - first
# - third