Use JSON when a program writes the file and a program reads it: API responses, stored records, anything crossing a network. Use YAML when a person writes it and has to understand it again six months later: CI pipelines, Kubernetes manifests, Docker Compose, application settings. YAML buys you comments, readable multi-line strings and far less punctuation. You pay for that with indentation that carries meaning, a much larger specification, and a type system that will eventually turn the country code NO into false. The two are not really competitors — since YAML 1.2, every valid JSON document is also valid YAML — so the real question is which one you write by hand.
The same data, both ways
In JSON:
{
"name": "build",
"retries": 3,
"branches": ["main", "release/*"],
"env": { "NODE_ENV": "production" }
}
In YAML:
# the nightly build
name: build
retries: 3
branches: [main, "release/*"]
env:
NODE_ENV: production
Both produce the same object. YAML drops the braces, the quotes around keys and every comma, and adds a comment that JSON has no way to express. Note the branches line: that is JSON syntax, still legal inside a YAML file. Mixing the two styles is normal, and for short lists it is usually the clearer one.
What YAML has that JSON does not
Comments. This is the big one, and the reason almost every configuration format that started as JSON has drifted toward something else. A config file without a place to write "leave this at 3, higher values trip the rate limiter" is a config file that accumulates decisions nobody can explain. JSON's designer removed comments on purpose, because people had begun using them to carry parsing directives.
Multi-line strings you can read. A shell script or a PEM certificate inside JSON becomes one long line full of \n escapes. YAML has block scalars: | keeps the line breaks exactly as written, > folds the lines into a paragraph. Both strip the surrounding indentation, so the text does not carry your file's layout into the value.
Several documents in one file. The --- separator lets one file hold a list of unrelated objects, which is why a Kubernetes deployment, service and ingress usually ship as a single YAML file. JSON has no equivalent; the nearest thing is JSON Lines, one compact object per line.
Reuse. Anchors and aliases (&defaults and *defaults) let you define a block once and point at it later; merge keys (<<) splice it into another mapping. This is also the first feature to cause trouble: most tools cannot round-trip an alias back out, parsers disagree about merge ordering, and a few nested aliases can expand a tiny file into gigabytes of memory — a denial-of-service trick old enough to have a nickname, the YAML bomb.
What JSON has that YAML does not
One obvious way to write everything. JSON's entire grammar fits on a single page of railroad diagrams. YAML has three ways to write a string — plain, single-quoted, double-quoted — two block-scalar styles with their own trailing-newline modifiers, flow style, block style, and a chapter's worth of rules about where whitespace may go. That flexibility is why two people editing the same YAML file produce diffs that disagree on style.
A parser in the standard library. Python, JavaScript, Go and the rest all read JSON with nothing installed. YAML almost always means a dependency, and which dependency matters, because parsers differ on the very cases that bite.
Whitespace that means nothing. You can minify JSON, paste it into a form field, wrap it in a shell variable or email it, and it survives. Paste YAML into anything that reindents it and you have changed the data. This is also why JSON is what travels over the wire and YAML is what sits in a repository.
No implicit typing. In JSON a quoted thing is a string and an unquoted thing is a number, true, false or null. There is nothing to guess. YAML resolves unquoted scalars by pattern, which is the source of every item in the next section.
Where YAML bites
The Norway problem
YAML 1.1 treated yes, no, on and off as booleans. So a list of country codes containing an unquoted NO arrives as false, and the on: key at the top of a GitHub Actions workflow is, under those rules, the boolean true rather than the word. YAML 1.2 narrowed booleans to true and false only, but plenty of parsers still behave like 1.1 — PyYAML's default loader among them — so the answer depends on which library reads your file. Quoting the value fixes it under every version, which is why careful config files quote almost everything. The converter on this site defaults to the 1.2 rule and has a switch that reparses the file under the 1.1 rules. Flipping it is the quickest way to see which of your unquoted values are about to change meaning in front of an older parser.
Numbers that change shape
Write version: 1.0 and you get the float one, which most emitters print back as 1 and which no longer matches the string "1.0". Write 1.2.3 and the two dots keep it a string. An ID of 17 digits or more loses precision the moment it passes through anything built on JavaScript numbers, because the largest integer those represent exactly is 9,007,199,254,740,991. Under 1.1 rules 12:30 was base-60 notation and arrived as the integer 750, which is how a list of times turns into a list of minute counts. Quote anything whose exact text matters.
Indentation is the syntax
There are no braces to tell you where a block ends, so a value at the wrong margin does not fail — it attaches to a different parent and the file still loads. Tabs are not merely discouraged as indentation; the specification forbids them, and the error you get rarely says so. Two spaces per level is the convention, and consistency inside a block matters more than the number you pick.
Duplicate keys
The specification calls two equal keys in one mapping an error. Many parsers shrug and keep the last one, so a setting added at the bottom of a long file can silently override the same key 200 lines up. When a change appears to have no effect, check this first.
Where JSON bites
No comments. No trailing comma either, which turns a one-line addition into a two-line diff and is a common cause of a config file failing to load. No NaN or Infinity. And duplicate keys are not forbidden there either: RFC 8259 says object names should be unique but stops short of requiring it, and parsers generally keep the last.
The other cost is readability at scale. A 400-line JSON config with everything quoted is hard to scan, and a minified one is impossible — which is why re-indenting it is usually the first step in reading someone else's API response, a technique the guide to formatting minified JSON covers properly.
One trap belongs to both formats. A secret in a Kubernetes manifest looks scrambled because it is base64, and base64 is an encoding, not encryption — anyone who can read the file can read the secret.
Converting between them
Sooner or later something downstream only accepts JSON — a schema validator, an HTTP request body, a command-line filter — and you have YAML. Because YAML is the superset, that direction is mostly mechanical, and a converter that runs in the browser does it without the file leaving your machine — which matters here, because config files are exactly the sort of thing that still holds a token someone forgot to remove.
What does not survive the trip is everything JSON cannot express. Comments disappear. Anchors and aliases have to be resolved into duplicated structure, or rejected — the converter here stops with a line number rather than guessing. Only the first document of a multi-document file comes across, and you get told how many there were. The reverse direction needs no converter at all: valid JSON is already valid YAML, so you can drop it into a .yaml file as it stands. It will read like JSON until someone reflows it into block style, but nothing is lost.
So which one?
- An API payload, a log line, a cache entry, a message on a queue — JSON. Every runtime already speaks it, and nothing about it depends on whitespace.
- A pipeline definition, a deployment manifest, an app config someone will edit — YAML, for the comments alone.
- A file a program writes and a person occasionally reads — JSON, indented two spaces. Generating correct YAML is harder than generating correct JSON.
- Anything where an error must be caught at the door — JSON with a schema. YAML validates against a JSON Schema too, since the data model is the same, but you are trusting the parser to have given you the values you meant.
When something downstream insists on JSON, the YAML to JSON converter here translates the file in your browser and tells you, with a line number, which features it refuses to fake rather than handing back a plausible-looking result. It also shows the key count and depth, which is a quick way to confirm the structure came out the shape you expected.
If the file you are wrestling with is data rather than configuration, converting a CSV into JSON has its own list of things the conversion quietly changes — leading zeros, dates and stray quotes being the usual casualties.
Frequently asked questions
Is YAML better than JSON?
Neither is better in general; they are aimed at different readers. YAML is better for configuration a person edits, because it has comments, multi-line strings and much less punctuation. JSON is better for data moving between programs, because it has one obvious spelling, no significant whitespace and a parser in every standard library.
Is JSON valid YAML?
Yes. YAML 1.2 defines the format as a superset of JSON, so any valid JSON document parses as YAML to the same value, and you can paste a JSON fragment straight into a YAML file. The reverse is not true: comments, anchors, block scalars and multi-document files have no JSON equivalent.
Why does YAML turn no into false?
Because YAML 1.1 treated yes, no, on and off as booleans, and many parsers still follow those rules, including PyYAML’s default loader. YAML 1.2 narrowed booleans to true and false only. Quoting the value fixes it under every version, which is why country codes and version numbers appear quoted in careful config files.
Can you put comments in JSON?
Not in standard JSON. There is no comment syntax and a strict parser will reject the file. The usual workarounds are a dummy key such as "_comment" or a dialect like JSON with Comments, which is what Visual Studio Code uses for its own settings. If comments matter to you, that is an argument for YAML.
Is YAML slower to parse than JSON?
Usually, and often by a wide margin, because YAML has a far more complicated grammar while JSON parsers tend to be native code built into the runtime. For a config file read once at startup it does not matter. For thousands of documents in a loop it does, which is a reason to convert once and keep the JSON.
Last updated September 19, 2026