YAML vs JSON: Syntax Differences, Trade-offs and Parser Traps
Your CI pipeline is green on your machine and red on the runner — the config is valid YAML and the only difference is the parser version. Or: a value you expected to be the string on was read as boolean true, so a feature flag silently enabled itself in production.
Neither is a YAML bug. Both are the same lesson: YAML is not "JSON with nicer syntax" — it is a different data model with implicit typing and indentation-sensitive structure, and a file that looks obviously correct can parse into something you did not write.
The problem: two formats, one confusing overlap
JSON is deliberately small: objects, arrays, strings, numbers, booleans, null. Each is written explicitly, indentation is cosmetic, and there are no comments. That strictness is its main advantage — a JSON parser either produces your data or fails, and cannot make decisions on your behalf.
YAML is a superset that adds comments, human-readable indentation, anchors and aliases, multiple documents per file, and implicit type conversions inherited from the 2001 specification. Each addition is useful, and each is a place where your file and your program's idea of the file can diverge. The practical summary: JSON gives you a data structure; YAML gives you a document a human writes and a program reads.
The three differences that actually bite
Indentation is structure. YAML uses whitespace to express nesting, with no delimiter to rescue a mistake. A tab where a space is expected is an error in most parsers. The failure is rarely subtle — you get an error pointing at a line number unrelated to the mistake.
Types are inferred. YAML resolves unquoted scalars against a type list before you see them:
| What you wrote | What the parser gives you |
|---|---|
yes, no, on, off | boolean true / false (YAML 1.1) |
2026-10-08 | a date object, not a string |
1.0.0 | a string (good — but 1.0 becomes a float) |
null, ~, empty | null |
0755 | octal in YAML 1.1, a string in 1.2 |
The rule that prevents all of it: quote anything whose type matters. A version string, an API key that looks numeric, a date you want treated as text.
Comments exist, so tooling must preserve them. JSON has no comment syntax, so every parser handles every JSON file identically. YAML comments are stripped by the parser, so a tool that rewrites a YAML file destroys them unless it round-trips through a full AST. This is the strongest practical argument for JSON in machine-generated files.
A trap worth naming: duplicate keys
Given a mapping with the same key twice, implementations disagree: many keep the last value, some raise an error, some keep the first. The specification leaves this undefined, so you cannot rely on any of it.
Duplicate keys usually arrive through merging — a base config plus an overlay, both setting timeout, merged by naive text concatenation rather than a real YAML merge. If a value "changes back" to something unexpected in a deployed environment, look for the same key in two files, because the parser's choice of winner is not portable.
The solution: pick per file, not per project
Use JSON when the file is generated by a tool, produced by an API, consumed by many languages, or must be diff-friendly and machine-owned — lockfiles, API response bodies, schema definitions. Strictness also means an error surfaces at parse time rather than as a silently wrong value.
Use YAML when a human writes and reads the file often: CI pipelines, Kubernetes manifests, docker-compose, application configuration where comments explain why a value is what it is. The indentation and comment support pay for themselves the first time someone needs to understand a value six months later.
Two patterns blur the line. JSON is a strict subset of YAML, so any JSON document is valid YAML — which is why a YAML parser can read JSON, and why converting JSON to YAML never fails on syntax. The reverse is where the real work happens: converting YAML to JSON is where comments are lost and ambiguous scalars are silently mistyped — which is how you find out what your config actually means.
The round trip is a review tool
Running a config through YAML → JSON shows what a parser will really produce: types you did not intend (unquoted on as true, an unquoted date as a date object), anchors expanded into full duplicated copies, and duplicate keys resolved one particular way. If the JSON surprises you, fix the YAML rather than patching the value downstream.
Tool walkthrough: converting safely between the two
Converting by hand is where errors creep in, because both directions have a failure mode easy to miss by eye.
For JSON to YAML, the JSON to YAML converter converts as you type, so you can keep editing either side. The one thing to check in the output is quoting: a JSON string that looks like true or 2026-10-08 comes back from a YAML parser as a boolean or a date unless the converter quoted it.
For YAML to JSON, the YAML to JSON converter is where you meet the implicit typing above. Anything that changed type is a line needing quotes: a mode: on that becomes "mode": true is not a converter bug, it is a boolean you should have quoted.
For cleanup, the YAML prettifier normalises indentation and key order, worth running on any file several people have edited. Inconsistent indentation is legal YAML and unreadable to a reviewer, and normalising it turns the next diff into something reviewable.
If a conversion fails to parse, the error is nearly always one of three things: tabs used for indentation, a colon inside an unquoted value (url: http: //example.com parses as a mapping), or a value beginning with a character YAML treats as syntax — @, *, &, % — which need quoting.
A note on YAML implementations
"A YAML parser" hides a real fork. YAML 1.1 (PyYAML, Ruby) treats yes, no, on and off as booleans and reads leading-zero numbers as octal. YAML 1.2 (Go's gopkg.in/yaml.v3) does not — only true and false are booleans. A config that works under PyYAML and breaks under a Go service is not broken YAML; it is two specifications disagreeing.
This is the argument for quoting aggressively: an explicitly quoted value has one interpretation under every implementation, removing an entire category of "works on my machine".
FAQ
Is JSON valid YAML? Yes — YAML is a strict superset of JSON, so any JSON document parses as YAML. The reverse does not hold: anchors, comments and multi-document files have no JSON equivalent, which is why YAML to JSON is the lossy direction.
Should I use YAML or JSON for a config file? Use YAML when a human writes and reads the file, especially when values need comments explaining intent — CI pipelines, Kubernetes manifests, compose files. Use JSON when the file is machine-generated, consumed by many languages, or needs byte-stable diffs.
Why does my YAML value become a boolean or a date? YAML infers the type of an unquoted scalar from its content: yes, no, on, off, true and false are booleans, and 2026-10-08 is a date. Quote any value whose type matters — "on", "2026-10-08", "1.0".
More developer tools on DigDevBox
- YAML to JSON converter — see exactly what a parser makes of your config
- JSON to YAML converter — rewrite a machine-generated file as readable YAML
- YAML prettifier — normalise indentation so diffs become reviewable
- JSON Formatter & Validator — validate the JSON side of a conversion