YAML vs JSON: which should you use for config and data?
By Andrew Butson · July 2, 2026 · 7 min read
Reach for YAML when a person is going to read and hand-edit the file, such as configuration for Kubernetes, GitHub Actions, Docker Compose or Ansible, because indentation reads cleanly and comments can explain the non-obvious bits. Reach for JSON when the file is generated and consumed by code, especially across an API boundary, because its stricter, bracket-delimited grammar parses identically everywhere with no room for ambiguity. Both describe exactly the same kind of data: nested maps, lists and scalar values. The difference is who is expected to look at the raw file.
YAML and JSON solve the same problem, writing down structured data as plain text, and, underneath the punctuation, they describe the same shape: objects with named fields, ordered lists, strings, numbers, booleans and null. Convert one to the other and nothing about the data itself changes, only how it is written on the page.
What differs is the audience each format was built for. JSON was lifted almost directly from a JavaScript object literal to move data between a browser and a server, so it favours a grammar a parser can validate in one obvious way. YAML set out to be comfortable for a person to write and read by hand, so it favours indentation over brackets and allows things such as comments, unquoted values and multi-document files that make sense for a human author but complicate a strict grammar.
| YAML | JSON | |
|---|---|---|
| Readability | Indentation-based, reads like outline notes | Bracket-delimited, denser on the page |
| Comments | Yes, with # | No native comment syntax |
| Syntax strictness | Looser — whitespace-sensitive, some implicit typing | Strict — one way to write anything |
| Parsing | Needs a YAML library in most languages | Built into almost every language's standard library |
| Data types | Strings, numbers, booleans, null, dates, anchors | Strings, numbers, booleans, null, arrays, objects |
| Common foot-gun | Unquoted values silently reinterpreted (e.g. "NO" read as false) | A stray trailing comma breaks the whole file |
| Typical home | Config files: Kubernetes, CI pipelines, Docker Compose | APIs, data interchange, JavaScript app config |
| File extension | .yaml / .yml | .json |
Two ways to write the same tree of data
Both formats were finalised the same year (2001) for very different audiences. JSON was formalised by Douglas Crockford as a lightweight subset of JavaScript's own object literal syntax: braces for objects, square brackets for arrays, quoted strings for keys. It was designed to be trivial for a machine to generate and parse, and it succeeded so completely that it is now built into the standard library of almost every programming language in use.
YAML (the name is a recursive joke, "YAML Ain't Markup Language") set out to be comfortable for a human to write directly, without a code generator in the loop. Later versions of the YAML spec are, deliberately, a strict superset of JSON: any valid JSON document is also valid YAML. YAML just adds a second, friendlier way to write the same structures on top.
Why config files chose YAML
Indentation is the headline reason. A deeply nested YAML file reads like an outline — each level of nesting is a further indent, with no braces or trailing commas cluttering the page. For a Kubernetes manifest or a CI pipeline definition that might run to hundreds of lines, that difference in density adds up quickly.
Comments matter just as much in practice. JSON has no comment syntax at all. Crockford has said the omission was deliberate, so people wouldn't misuse comments as parsing directives, which means you cannot leave a note in a JSON config explaining why a particular value is set the way it is. YAML's # comments let you document the one setting that took an afternoon of debugging to get right, right next to the line it explains. That single feature is a large part of why Kubernetes, GitHub Actions, Docker Compose and Ansible all standardised on YAML for files a person is expected to maintain by hand.
Why APIs and code stuck with JSON
JSON's appeal is the mirror image of YAML's: strictness. There is exactly one correct way to write any given piece of data in JSON, which makes it trivial to validate, diff and generate programmatically: a server just serialises its internal data structure and the result is valid JSON, with no separate step to get the indentation or quoting right. That same rigidity is why virtually every language parses it natively rather than needing a third-party library, and why it has become the default body format for REST and GraphQL APIs.
Terseness helps too. Once a payload is machine-generated and machine-consumed, nobody is reading the raw file, so JSON never needed comments, folded strings or any of the readability features YAML added for a human author.
YAML's foot-guns
The flexibility that makes YAML pleasant to write also makes it easy to get subtly wrong. Because structure is defined by whitespace, mixing tabs and spaces (or a single stray space) can silently change what a block belongs to, sometimes without an obvious error. The YAML spec forbids tabs for indentation specifically because of how easily this goes wrong, but nothing stops an editor from inserting one anyway.
The more notorious problem is implicit typing: a bare, unquoted value in YAML is automatically interpreted as whatever type it looks like. The classic case is a two-letter country code like "NO" being read as the boolean false rather than the string "NO", because older YAML treats a family of unquoted words (yes/no, on/off, true/false) as booleans. A version string like 1.10 can similarly be read as the number 1.1, quietly dropping the trailing zero. The fix is simple once you know about it: quote any value that could be mistaken for a number, boolean or null. But it is a genuine trap for anyone writing YAML by hand for the first time. JSON has no equivalent hazard, because every value is unambiguously typed by its own syntax (quotes for strings, bare digits for numbers, literal true/false/null keywords for the rest).
The tooling split in practice
Look at where each format actually won and the pattern holds up. Kubernetes manifests, Helm charts, GitHub Actions workflows, Docker Compose files and Ansible playbooks are all YAML: every one of them is a file a developer or operator is expected to open, read top to bottom, and edit directly, often while debugging something that's already broken. Being able to add a comment explaining why a replica count is pinned to an odd number, or to scan a deployment's structure at a glance, matters more in that setting than saving a few characters.
REST and GraphQL APIs, npm's lockfiles, browser localStorage payloads and most inter-service messages went the other way, to JSON, because none of them are meant to be hand-edited at all. A server doesn't care whether a payload is easy on the eye; it cares that serialising and parsing it is fast, unambiguous and supported natively without pulling in a YAML library. Once a file's primary reader is another program, JSON's rigidity stops being a downside and becomes the whole point.
Converting between them
Because both formats describe the same tree of maps, lists and scalars, converting between them is a structure-preserving operation: Morphr parses the source into that tree and re-serialises it in the other syntax, so every key, value and level of nesting comes across intact.
The one thing that cannot survive the trip from YAML to JSON is anything that has no JSON equivalent: comments are dropped, since JSON has nowhere to put them, and YAML's anchors and aliases (its way of referencing an earlier block instead of repeating it) get expanded into their full, literal values rather than preserved as references. Going the other way, JSON to YAML, has no such asymmetry: every JSON value maps onto an equivalent YAML value with nothing left behind, and you simply don't get comments back that were never there to begin with.
Reach for YAML when…
- Writing configuration a person will read and hand-edit — Kubernetes, Docker Compose, CI pipelines, Ansible playbooks.
- You want inline comments explaining a non-obvious setting.
- The data is deeply nested and indentation makes the structure easier to scan than brackets would.
- You're comfortable quoting any value that could be mistaken for a number, boolean or null.
Reach for JSON when…
- The file moves over an API or between two programs, not primarily to a person.
- You want zero ambiguity and a parser built into the language already.
- Tooling needs to validate or diff the file against a strict, predictable grammar.
- Comments aren't needed and a compact, generated file matters more than hand-readability.
Turn a YAML config or data file into JSON in your browser, nothing is uploaded.
Runs entirely in your browser — nothing is uploaded.
Frequently asked questions
- Can I convert YAML to JSON without losing anything?
- The data itself comes across exactly: every key, value and nested structure survives. What is lost is anything JSON has no way to express: comments disappear, and YAML anchors/aliases (references to a repeated block) get expanded into their full values rather than kept as references.
- Why did my YAML boolean turn into false unexpectedly?
- YAML implicitly types unquoted values, and a family of words (yes/no, on/off, true/false) are read as booleans even when you meant a plain string. This is the well-known "Norway problem", where a country code like NO gets silently parsed as false. Quoting the value ("NO") fixes it.
- Is YAML just JSON with different syntax?
- Largely, yes — YAML 1.2 is defined as a strict superset of JSON, so any valid JSON file is already valid YAML. YAML then layers extra features on top: comments, multi-document files, anchors/aliases, and a looser, unquoted way to write scalar values.
- Which parses faster, YAML or JSON?
- JSON's simpler, stricter grammar is generally quicker to parse than YAML's. For typical config files the difference is not something you'd notice in practice; it only matters at the scale of parsing very large files repeatedly.