yq — Transforms
to_entries / from_entries
These are inverse operations that convert between maps and arrays of key-value pairs. This is the fundamental yq transform — most filtering depends on it.
to_entries — map to key-value array
cat <<'YAML' > /tmp/ports.yml
https: 443
ssh: 22
dns: 53
YAML
yq 'to_entries' /tmp/ports.yml
# Output:
# - key: https
# value: 443
# - key: ssh
# value: 22
# - key: dns
# value: 53
from_entries — key-value array back to map
cat <<'YAML' > /tmp/ports.yml
https: 443
ssh: 22
dns: 53
YAML
yq 'to_entries | map(select(.value > 100)) | from_entries' /tmp/ports.yml
# Output:
# https: 443
The pattern to_entries | map(transform) | from_entries is so common it has a shorthand: with_entries.
with_entries
Filter map keys — keep only port attributes
yq '.asciidoc.attributes | with_entries(select(.key | test("^port-")))' docs/antora.yml
# Output:
# port-https: "443"
# port-ssh: "22"
# port-kerberos: "88"
# port-ldap: "389"
# ...
with_entries(f) is exactly to_entries | map(f) | from_entries.
Use it when you want a filtered/transformed map, not an array.
Rename keys — strip prefix
yq '.asciidoc.attributes | with_entries(select(.key | test("^port-"))) | with_entries(.key |= sub("^port-"; ""))' docs/antora.yml
# Output:
# https: "443"
# ssh: "22"
# kerberos: "88"
# ldap: "389"
# ...
|= is the update operator — it modifies in place rather than replacing.
sub("pattern"; "replacement") does regex substitution on a string.
map
Transform every element in a sequence
cat <<'YAML' > /tmp/hosts.yml
- name: ise-01
ip: 10.50.1.20
- name: vault-01
ip: 10.50.1.60
- name: vyos-01
ip: 10.50.1.2
YAML
yq 'map(.name + " -> " + .ip)' /tmp/hosts.yml
# Output:
# - ise-01 -> 10.50.1.20
# - vault-01 -> 10.50.1.60
# - vyos-01 -> 10.50.1.2
Map with string interpolation
cat <<'YAML' > /tmp/hosts.yml
- name: ise-01
ip: 10.50.1.20
- name: vault-01
ip: 10.50.1.60
YAML
yq -r 'map("ssh evan@" + .ip + " # " + .name)[]' /tmp/hosts.yml
# Output:
# ssh evan@10.50.1.20 # ise-01
# ssh evan@10.50.1.60 # vault-01
sort_by
Sort entries by key name
yq '.asciidoc.attributes | to_entries | sort_by(.key) | .[:5]' docs/antora.yml
# Output: first 5 attributes alphabetically
# - key: ad-dc-hostname
# value: home-dc01.inside.domusdigitalis.dev
# - key: ad-dc-ip
# value: "10.50.1.50"
# ...
Sort by value (numeric context)
cat <<'YAML' > /tmp/ports.yml
- name: https
port: 443
- name: ssh
port: 22
- name: dns
port: 53
- name: ldaps
port: 636
YAML
yq 'sort_by(.port)' /tmp/ports.yml
# Output (ascending by port number):
# - name: ssh
# port: 22
# - name: dns
# port: 53
# - name: https
# port: 443
# - name: ldaps
# port: 636
Reverse sort
cat <<'YAML' > /tmp/ports.yml
- name: https
port: 443
- name: ssh
port: 22
- name: dns
port: 53
YAML
yq 'sort_by(.port) | reverse' /tmp/ports.yml
# Output: descending by port number
group_by
Group array elements by a field
cat <<'YAML' > /tmp/vlans.yml
- host: ise-01
vlan: 10
- host: vault-01
vlan: 10
- host: vyos-01
vlan: 1
- host: k3s-master
vlan: 20
YAML
yq 'group_by(.vlan)' /tmp/vlans.yml
# Output:
# - - host: vyos-01
# vlan: 1
# - - host: ise-01
# vlan: 10
# - host: vault-01
# vlan: 10
# - - host: k3s-master
# vlan: 20
group_by returns an array of arrays, grouped by the field value.
Count per group
cat <<'YAML' > /tmp/vlans.yml
- host: ise-01
vlan: 10
- host: vault-01
vlan: 10
- host: vyos-01
vlan: 1
- host: k3s-master
vlan: 20
YAML
yq '[group_by(.vlan)[] | {"vlan": .[0].vlan, "count": length}]' /tmp/vlans.yml
# Output:
# - vlan: 1
# count: 1
# - vlan: 10
# count: 2
# - vlan: 20
# count: 1
unique_by
Deduplicate by a field
cat <<'YAML' > /tmp/entries.yml
- host: ise-01
role: pan
- host: ise-01
role: mnt
- host: vault-01
role: secrets
YAML
yq 'unique_by(.host)' /tmp/entries.yml
# Output:
# - host: ise-01
# role: pan
# - host: vault-01
# role: secrets
unique_by keeps the first occurrence of each unique value.
flatten
Flatten nested arrays
cat <<'YAML' > /tmp/nested.yml
- - a
- b
- - c
- d
- - e
YAML
yq 'flatten' /tmp/nested.yml
# Output:
# - a
# - b
# - c
# - d
# - e
Flatten one level only
cat <<'YAML' > /tmp/deep.yml
- - - deeply
- nested
YAML
yq 'flatten(1)' /tmp/deep.yml
# Output:
# - - deeply
# - nested