JSON vs YAML: Key Differences (With Examples)
The main difference between JSON and YAML is syntax: JSON is strictly machine-readable with mandatory quotes and braces, while YAML is human-readable and uses indentation instead of punctuation. Both formats can describe the same data, and either converts to the other without information loss. Which one to use depends on who reads and edits the file.
JSON vs YAML at a Glance
JSON (JavaScript Object Notation) grew out of JavaScript and became the default format for APIs and data exchange. YAML (YAML Ain't Markup Language) was designed to be easy for humans to write and scan, which is why it dominates configuration files for Kubernetes, CI/CD pipelines, and Docker Compose.
Here is how the two formats compare feature by feature:
| Feature | JSON | YAML |
|---|---|---|
| Syntax | Braces, brackets, commas | Indentation and dashes |
| Comments | Not supported | # comments supported |
| Keys | Must be double-quoted strings | Bare words work |
| Strings | Always quoted | Quoting optional, with pitfalls |
| Booleans | Only true and false | true, yes, on and more (YAML 1.1) |
| Multiple documents | One per file | --- separates documents |
| Reusable blocks | Not supported | Anchors and aliases (&, *) |
| Typical uses | APIs, web responses, data exchange | Kubernetes, CI/CD, Docker Compose |
If you only remember one line from this table, make it this: JSON is written for machines first, YAML is written for humans first. That single distinction explains almost every difference below.
The Same Config in Both Formats
Nothing makes the difference clearer than seeing identical data side by side. First the JSON version:
{
"service": "invoice-api",
"replicas": 3,
"port": 8080,
"features": {
"cache": true,
"dryRun": false
},
"regions": ["eu-west-1", "us-east-1"]
}
Now the exact same data in YAML:
service: invoice-api
replicas: 3
port: 8080
features:
cache: true
dryRun: false
regions:
- eu-west-1
- us-east-1
Both files parse to the same in-memory object. The YAML version drops the quotes, braces, and commas, and a parser infers the structure from indentation. It reads faster for a human, but as the next section shows, that convenience has a cost: the parser now guesses more of your intent.
Three Differences That Actually Cause Bugs
1. The Norway problem: YAML turns words into booleans
In YAML 1.1 parsers, unquoted yes, no, on, off, and y/n are parsed as booleans, not strings. The classic example: country: no for Norway silently becomes country: false. JSON has no such ambiguity because its boolean values are only true and false. If a value in your YAML could accidentally read as a boolean or a number (think version: 1.10, which becomes the float 1.1), wrap it in quotes.
2. Indentation is syntax in YAML
In YAML, the number of spaces decides whether a key belongs to one object or another. Tabs are forbidden outright, and a two-space slip can turn a list item into a map value without any error at parse time. JSON's explicit braces and commas make the structure unambiguous, and any formatter can reformat broken JSON mechanically. YAML mistakes are quieter: the file still parses, it just means something different from what you meant.
3. JSON has no comments
This is JSON's most requested missing feature. Teams that keep JSON configuration files often resort to "comment": "..." dummy fields or strip comments out before deployment. YAML supports # comments anywhere, which is one of the biggest reasons configuration-heavy tools like Kubernetes prefer it.
How to Convert Between JSON and YAML (Step by Step)
Because both formats describe the same data model, conversion is mechanical. Here is a reliable routine:
Step 1: JSON to YAML with yq. If you have yq installed, one command handles it:
yq -P '.' config.json > config.yaml
The -P flag outputs pretty-printed YAML.
Step 2: YAML back to JSON. The reverse direction is the same tool with a different output flag:
yq -o=json '.' config.yaml > config.json
Step 3: Round-trip check in Python. For config files you care about, verify the conversion did not lose anything:
import json, yaml
with open("config.json") as f:
data = json.load(f)
yaml_text = yaml.safe_dump(data, sort_keys=False)
print(yaml_text)
back = yaml.safe_load(yaml_text)
assert back == data # round-trip check
Step 4: Quote anything suspicious. Before you commit the YAML, scan for unquoted values that look like no, on, off, version strings such as 1.10, or anything with a leading zero. Quoting them costs nothing and prevents the silent coercion bugs described above.
Frequently Asked Questions
Is YAML a superset of JSON?
Yes. Every valid JSON document is also valid YAML 1.2, which is why YAML parsers can read JSON configuration files directly. The reverse is not true: YAML comments, anchors, and multi-document files have no JSON equivalent, so converting YAML to JSON can lose those.
Which is faster to parse, JSON or YAML?
JSON, by a wide margin. Its grammar is simple enough for fast, low-memory parsers, while YAML's full spec requires more complex parsing logic. Benchmarks commonly show JSON parsing several times faster than YAML. For API payloads and machine-to-machine traffic, JSON is the right default; YAML belongs where humans are the primary editors.
Should I use YAML or JSON for my project?
Ask one question: who edits this file most often? If it is machines (APIs, generated files, logs), use JSON. If it is humans (deployment manifests, CI pipelines, local developer config), YAML's comments and lower punctuation noise usually win — provided you quote ambiguous values and stay consistent with indentation.
Validate Before You Ship
Whatever format you pick, most configuration bugs start as silent syntax slips: a missing comma, a mis-indented block, an unquoted no. The cheapest fix is to validate the file before it reaches production. Paste your JSON into Utilvy's free JSON Formatter to catch syntax errors, reformat it cleanly, and inspect nested structures at a glance. And if you are aligning YAML keys with your JSON API's naming style, the Case Converter keeps snake_case, camelCase, and kebab-case consistent across both files.