How yq Compares to jq, and What Features Are Missing
Updated
yq is a command-line processor that borrows jq's filter syntax but applies it to YAML, JSON, INI, XML, properties, CSV, and TSV files. If you already know jq, most common expressions — .a.b[0].c, assignments like .a.b[0].c = "cool", and strenv() for environment variables — carry over directly. The gaps are at the edges: yq does not yet implement everything jq does, and its handling of comments and whitespace, while deliberate, is not exhaustive. The sections below cover where the two tools align, where they diverge, and what to check before relying on yq for a given task.
Where yq and jq Align
yq's documentation describes it as using "jq like syntax" while working across YAML and other formats, not just JSON. In practice this means:
- Path expressions work the same way.
yq '.a.b[0].c' file.yamlreads a nested value, and piping from STDIN withyq '.a.b[0].c' < file.yamlbehaves as you would expect from jq. - In-place updates are a first-class operation:
yq -i '.a.b[0].c = "cool"' file.yamlrewrites the file directly. - Environment variable injection uses the same
strenv()function:NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml. - Multi-file merging is supported through
load()and reduce expressions, e.g.yq -n 'load("file1.yaml") * load("file2.yaml")', or glob-based merging withyq ea '. as $item ireduce ({}; . * $item)' path/to/*.yml.
The documentation states that yq "does support the most common operations and functions, and more is being added continuously." So for everyday read, update, and merge work, the jq mental model transfers without much friction.
Where yq Diverges from jq
The most important difference is scope of formats. jq is a JSON processor; yq is built for YAML first and extends to JSON, XML, INI, properties, CSV, and TSV. If your pipeline is JSON-only, jq remains the more complete implementation. If your pipeline touches YAML — Kubernetes manifests, CI configs, application settings — yq is the tool that understands the format natively rather than requiring a JSON round-trip.
A second difference is distribution. yq is written in Go, so the documentation notes you can "download a dependency free binary for your platform and you are good to go," with additional options through package managers, Docker, and Podman. That matters in minimal containers or air-gapped environments where installing a runtime is inconvenient.
Known Limitations to Plan Around
The documentation's "Known Issues / Missing Features" section names two concrete caveats:
- Comment and whitespace preservation is best-effort. yq "attempts to preserve comment positions and whitespace as much as possible, but it does not handle all scenarios," with a pointer to the underlying go-yaml v3 library for details. If your YAML files carry meaningful comments — annotated configs, documented manifests — verify the output after an in-place edit rather than assuming comments survive untouched.
- PowerShell quoting is problematic. The docs note that "Powershell has its own... opinions on quoting yq." On Windows, expect to adjust quoting or escape characters when passing filters, and consult the project's tips and tricks page for common workarounds.
Beyond these, the docs are explicit that yq "doesn't yet support everything jq does." The safe approach: if a filter depends on an advanced jq builtin, test it against your actual yq version before committing it to a script. The documentation index (llms.txt) and the recipes page are the places to confirm current coverage.
Choosing Between Them
| Consideration | Lean toward jq | Lean toward yq |
|---|---|---|
| Input format | JSON only | YAML, XML, INI, properties, CSV/TSV |
| Filter complexity | Advanced or uncommon jq builtins | Common path reads, assignments, merges |
| Comment preservation | Not applicable | Needed, but must be verified after edits |
| Deployment | Runtime available | Prefer a dependency-free binary, Docker, or Podman |
| Shell environment | Bash/zsh | PowerShell requires quoting care |
A practical pattern is to prototype the filter in jq against a JSON export, then port it to yq once you confirm the expression is within yq's supported set — and re-run it against the real YAML to catch comment or formatting changes.