yq: mikefarah (Go) vs kislyuk (Python) Differences
There are two different tools named yq: mikefarah/yq (Go, standalone) and kislyuk/yq (Python, a jq wrapper). They take different syntax.
The number one real-world yq failure in CI is a script written for one yq running on the other. Knowing which one a runner has, and how their syntax diverges, prevents hours of confusion.
What it does
mikefarah/yq is a self-contained Go binary with its own expression language and does not need jq. kislyuk/yq is a thin Python wrapper that converts YAML to JSON, pipes it through jq, and converts back, so it needs jq installed and uses jq syntax. Same command name, different engines.
How to tell them apart
yq --version
# Go: yq (https://github.com/mikefarah/yq/) version v4.x.x
# Python: yq 3.x.x
yq --help | head -1 # Python mentions jq; Go does notKey differences
| Aspect | mikefarah (Go) vs kislyuk (Python) |
|---|---|
| In-place edit | Go: -i with = assignment; Python: -i is jq-arg, no = operator |
| Default output | Go: YAML; Python: JSON (use -y for YAML) |
| Engine | Go: built-in; Python: shells out to jq |
| Comments | Go: preserved on edit; Python: dropped (round-trips via JSON) |
| Env vars | Go: strenv()/env(); Python: jq env.VAR |
| Merge | Go: * operator, eval-all; Python: jq -s slurp |
In CI
Pin the implementation explicitly. Installing mikefarah/yq from its GitHub release binary avoids picking up the Python one from pip or a distro package. Add a guard step: yq --version | grep -q mikefarah || { echo "wrong yq"; exit 1; }.
Common errors in CI
Symptoms of running a Go-yq script on Python yq (or vice versa): "= " assignments do nothing, getting JSON when you expected YAML, comments disappearing, strenv()/eval/eval-all reported as unknown, or -i not editing in place. The fix is not to rewrite the expression but to install the yq the script targets, then verify with yq --version.