formaterTools Logo Formater Tools

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 &name and 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.