Converting YAML to JSON With yq and Back Again Cleanly
yq converts YAML to JSON and back in one command. The same file gave different JSON in yq and PyYAML, and a big integer made yq fail. Flags and traps.

YAML to JSON is the most common conversion in a developer's day: feeding a manifest to a tool that wants JSON, putting a config through jq, checking what a parser sees. yq does it in one command, and the conversion looks trivial because YAML is nearly JSON. It is not trivial, and the details of what changes are the subject here. This post gives the flags, then the differences I found between yq and Python on the same file, and the cases where conversion is lossy.
The flags
yq -o=json '.' file.yaml # YAML to indented JSON
yq -o=json -I=0 '.' file.yaml # compact, one line
yq -p=json -o=yaml '.' file.json # JSON to YAML
yq -P '.' file.json # pretty-print: JSON in, block YAML out-o sets the output format and -p the input format; the input format is guessed from the file extension, and needs -p when you read from standard input. -I=0 sets the indent to zero, which gives compact JSON. For a multi-document YAML stream each document becomes its own JSON value:
printf 'a: 1\n---\na: 2\n' | yq -o=json -I=0 '.' -{"a":1}
{"a":2}That is JSON Lines, one object per line, the format jq -c and most log tools expect. Use yq eval-all with [.] if you want one JSON array instead.
One file, two JSONs
The test file:
# top comment
base: &b {host: db, port: 5432}
prod:
<<: *b
host: prod-db
when: 2026-10-27
ver: 3.10
country: NO
flag: yes
nothing: ~
1: one
multi: |
line one
line twoyq -o=json '.' gave:
{
"base": {"host": "db", "port": 5432},
"prod": {"port": 5432, "host": "prod-db"},
"when": "2026-10-27",
"ver": 3.10,
"country": "NO",
"flag": "yes",
"nothing": null,
"1": "one",
"multi": "line one\nline two\n"
}(Indentation condensed for reading.) Python, with json.dumps(yaml.safe_load(...), default=str):
{"base": {"host": "db", "port": 5432}, "prod": {"host": "prod-db", "port": 5432}, "when": "2026-10-27", "ver": 3.1, "country": false, "flag": true, "nothing": null, "1": "one", "multi": "line one\nline two\n"}Compare the differences. country: NO is the string "NO" in yq and false in Python. flag: yes is "yes" in yq and true in Python. ver: 3.10 is written as 3.10 by yq (valid JSON, a number whose digits keep the zero, though any JSON reader will load it as 3.1) and as 3.1 by Python. The same file, two different documents, because the two tools implement different versions of YAML (YAML 1.1 versus 1.2). When you convert to feed another tool, the consumer reads the JSON the same way regardless of how you made it, so the choice of converter decides what that tool sees. Know which YAML rules your real consumer applies, and convert with the matching tool, or quote the ambiguous values in the YAML.
Things that were the same: the date became a string in both ("2026-10-27"), the null stayed null, the integer key 1 became the string "1" (JSON keys are strings), and the block scalar kept its newlines. The anchor and merge key expanded: prod holds port from the anchor and its own host. The comment is gone, as JSON has nowhere to put it.
When the conversion fails
A value that does not fit the target's number model stops yq:
Error: json: error calling MarshalJSON for type *yqlib.CandidateNode: strconv.ParseInt: parsing "12345678901234567890": value out of rangeAn integer of twenty digits exceeds 64 bits, and yq refused to convert the file. Python read the same value as an arbitrary-precision integer and wrote it out. JSON itself places no limit on digits, but many JSON consumers (JavaScript, for one) cannot hold integers above 2^53 exactly, so even where a converter succeeds the number may change downstream. Identifiers that are this long should be strings. If a file with big numbers must convert, quote them in the YAML, or use a converter that keeps arbitrary precision.
Also watch for:
Non-string keys. YAML allows any scalar as a key. JSON requires strings, so 1: becomes "1", and on: can become true or "on" depending on the tool. Two keys that collapse to the same string merge, losing data.
Special floats. .inf and .nan have no JSON representation. Converters differ: some emit null, some fail, some emit Infinity, which is not valid JSON.
Binary and custom tags. !!binary values become base64 strings, and unknown tags are dropped or cause errors.
Timestamps. Dates become strings in ISO form, not date types, because JSON has none.
Duplicate keys. yq passes both entries into its internal tree, and JSON with duplicate keys is legal syntax that most readers resolve by keeping the last. Lint the source first.
JSON to YAML
The reverse is simpler, and has one trap of its own:
echo '{"a":[1,2],"b":{"c":null},"d":"3.10","e":"NO"}' | yq -p=json -o=yaml '.'a:
- 1
- 2
b:
c: null
d: "3.10"
e: NOThe string "3.10" was written with quotes, so a reader keeps it as text. The string "NO" was written without quotes, since to a YAML 1.2 emitter NO is a plain string. PyYAML will read that e: NO as false. Converting JSON to YAML for a consumer that implements 1.1 requires quoting strings that 1.1 would reinterpret, and yq does not do that by default. Force quoting with style: yq -p=json -o=yaml '.. style="double"' writes every scalar and key with double quotes, which is safe and noisy, or quote selected paths. Then load the result with the real parser and compare.
A conversion checklist
Know the consumer's YAML version and choose the converter, or the quoting, to match.
Convert, then load both sides in the same language and compare the data. For a YAML to JSON conversion:
json.loads(converted) == yaml.safe_load(original)shows exactly where the two tools disagree.Check numbers wider than 53 bits and floats with trailing zeros.
Check keys. Integer and boolean-looking keys, and collisions after stringification.
Expect comments to vanish, and keep the YAML as the source of truth.
Validate the JSON against a schema if one exists.
**Pin the
yqversion** in scripts, and watch for warnings. The output above came with a warning about merge-anchor behavior that is changing, which tells you that results for anchored files may change with the version.
For a look without any tooling, paste YAML into the YAML to JSON tool, which shows the JSON and the types.
Related reading
The cluster hub is working with YAML from the terminal. Comparisons of the formats are in YAML versus JSON for configuration, and the Python side of the conversion in reading and writing YAML in Python safely. yq's format handling is in the yq documentation on formats, and JSON in RFC 8259.
When a YAML to JSON conversion cannot be lossless
The YAML uses comments or anchors for meaning. Both vanish or expand. Keep the YAML as the source.
Types are ambiguous. Without quotes in the source, two parsers disagree. Fix the source.
Numbers are large or precise. Quote them as strings.
The target has a schema. Convert, then validate, then fix the YAML. Do not hand-edit the JSON.


