YAML vs JSON for Config Files: The Real Trade-offs
Open a Docker Compose file and a package.json side by side and the difference in "feel" is obvious before you even read the content - one leans on indentation and reads almost like prose, the other is fenced in by braces and quotation marks on every line. That's not a cosmetic accident. YAML and JSON are solving overlapping problems with different priorities, and picking between them for a config file is really a choice about who's going to be reading and editing it, and how forgiving you need the format to be.
Readability: Indentation vs Brackets
JSON nests structure using explicit brackets and commas - every object is wrapped in
{ }, every array in [ ],
every key-value pair separated by a comma from the next. That's unambiguous but visually noisy, especially once
you're several levels deep and counting closing braces to figure out which object you're actually inside. YAML
drops almost all of that punctuation and uses indentation to express nesting instead, the same way Python uses
whitespace instead of braces. The result reads closer to a plain list than a data structure:
database:
host: localhost
port: 5432
credentials:
user: admin
password: secret
The same structure in JSON needs a closing brace for every level you opened, plus commas between every sibling key. For a config file a human is going to hand-edit regularly - a CI pipeline definition, a docker-compose file, an Ansible playbook - that difference in visual noise adds up. For a payload passed between two services that never gets hand-edited, it usually doesn't matter, because nobody's eyes are on it.
What YAML Has That JSON Doesn't
-
•
Comments. JSON has no comment syntax at
all - not even a convention that most parsers tolerate. YAML supports
#comments anywhere, which matters enormously for config files where you want to explain why a value is set the way it is, not just what it's set to. -
•
Anchors and aliases. YAML lets you define a
block once with
&nameand reuse it elsewhere with*name, which is how tools like Docker Compose let you define a shared set of environment variables or resource limits once and apply them to several services without copy-pasting the same block repeatedly. JSON has no equivalent - every repeated value has to be typed out in full each time. -
•
Multi-document files. A single YAML file
can contain several separate documents divided by a
---line - Kubernetes manifests lean on this constantly to define multiple resources (a Deployment and a Service, say) in one file. JSON has no built-in way to concatenate multiple top-level documents into one file.
The Classic YAML Gotcha: Whitespace and Implicit Types
YAML's readability comes at a real cost: since structure is defined by indentation rather than explicit delimiters, an inconsistent indent - especially mixing tabs and spaces, which the YAML spec forbids for indentation but which plenty of editors will insert without warning you - can silently change what a value belongs to, or throw a parse error that's genuinely hard to spot by eye in a long file. Two spaces of indentation instead of four doesn't just look different, it can nest a key under the wrong parent entirely with no error at all.
The other classic gotcha is implicit type coercion. Under the YAML 1.1 spec that many older and more permissive
parsers still follow, unquoted words like yes,
no, on, and
off get silently parsed as booleans, not strings. This became
infamous as the "Norway problem" - a country code field containing the unquoted value
NO (Norway's ISO code) gets coerced to the boolean
false by parsers that follow that older spec. The fix is simple
once you know about it - quote any value that could be misread as a boolean, number, or null - but it's the
kind of bug that's invisible until it silently breaks something downstream.
Where JSON Still Wins
For anything that crosses a wire between two programs - API request and response bodies, event payloads, anything generated and consumed entirely by code - JSON's strictness is an advantage, not a limitation. There's exactly one way to interpret a given JSON document, every mainstream language has a fast built-in or first-party parser for it, and there's no indentation-sensitivity or implicit-typing surprise waiting to bite a machine-generated payload that no human will ever manually edit. That universal, unambiguous parsing support is precisely what JSON was designed to guarantee, and it's why virtually every REST and JSON-RPC API still uses it as the wire format even in a YAML-friendly ecosystem.
Converting Between Them
If you need to move a document between the two formats, the
YAML to JSON Converter
and JSON to YAML Converter
on this site handle the common case well: standard key-value nesting, block-style lists, quoted and unquoted
scalars, and inline flow-style arrays and objects. Worth knowing before you lean on them for anything more
exotic: the YAML-to-JSON parser recognizes only the literal words true
and false as booleans, not the yes/no/on/off
variants some YAML 1.1 parsers coerce - so it won't reproduce the "Norway problem" gotcha described above, but
it also won't match a stricter parser's behavior if your source YAML relies on that coercion intentionally. It
skips # comment lines during parsing rather than raising an error
on them, but comments obviously can't survive into JSON output since JSON has nowhere to put them. Neither
converter supports anchors/aliases or multi-document ----separated
files - both are treated as a single plain document, so a Kubernetes-style multi-resource manifest or a
Compose file leaning on YAML anchors will need to be split or de-referenced by hand before converting.
