The two-line answer
- Wire format between programs? JSON. It's faster to parse, has no version drift, and every language ships a parser.
- Config file humans edit? YAML (or TOML). Comments, multiline strings, and less syntactic noise.
Decision table (skip ahead if you're picking right now)
| Your use case | Pick | Why |
|---|---|---|
| HTTP API response body | JSON | Every framework, WAF, and client library expects it |
| Kubernetes manifest | YAML | kubectl, Helm, Kustomize all speak YAML natively |
| GitHub Actions / GitLab CI / CircleCI workflow | YAML | Required by the tool — no JSON alternative |
| Logging / metrics output | JSON (NDJSON) | Splunk, Datadog, Loki, Elastic all expect JSON lines |
| Application config file | YAML or TOML | Editor-friendly; comments matter |
| OpenAPI / AsyncAPI spec | Either — both supported | YAML for editing, JSON for tooling |
| Embedded in a database column | JSON | Native column types in Postgres, MySQL, SQLite |
| Build cache / lockfile | JSON | Machine-written, never edited by hand |
Is "yml" the same as "yaml"?
Yes — .yml and .yaml are both valid file
extensions for the same YAML format. The official YAML site recommends
.yaml, but .yml is more common in practice
(GitHub Actions, Docker Compose, GitLab CI all default to it). Some
tools accept only one — Kubernetes manifests are usually
.yaml, GitHub workflows are .yml. Lock the
extension your tool expects; the parser doesn't care.
Side by side
The same data in both formats:
# YAML
name: my-app
version: 1.0.0
ports:
- 80
- 443
config:
debug: false
timeout: 30
# Retry logic was added in v1.0
retries: 3 // JSON
{
"name": "my-app",
"version": "1.0.0",
"ports": [80, 443],
"config": {
"debug": false,
"timeout": 30,
"retries": 3
}
}
Same data tree. YAML drops the braces, brackets, quotes, and
commas in exchange for caring about indentation. The
# comment in YAML has no JSON equivalent.
Quick syntax differences
| Feature | YAML | JSON |
|---|---|---|
| Comments | # inline | Not allowed |
| Trailing commas | N/A | Not allowed |
| Single quotes | Allowed | Not allowed |
| Unquoted keys | Default | Not allowed |
| Unquoted strings | Allowed (with caveats) | Not allowed |
| Multiline strings | Native (|, >) | Use \n in a single-line string |
| References / aliases | & and * | None |
| Multiple documents per file | Yes (--- separator) | No |
| Tabs allowed for indent | No (most parsers reject) | N/A — no indent |
| Spec size | ~80 pages | ~16 pages |
Where YAML wins
Configuration files
Kubernetes manifests, GitHub Actions, Ansible playbooks, Docker Compose, CircleCI configs — all use YAML, all for the same reason: humans read and edit these by hand. JSON's required quotes and commas make it painful for files larger than ~50 lines.
Multiline content
Embedding a SQL query, a shell script, or a long template in JSON
means escaping every newline as \n in a single string.
YAML's block scalars (| and >) keep
the content readable.
Multiline strings have their own
guide.
Repetition reduction
YAML's anchors (&name) and aliases
(*name) let you define a chunk of config once and
reuse it. JSON has no equivalent — you copy-paste or use a
templating system.
Anchors and aliases guide.
Where JSON wins
Speed
JSON parsers are 5-50× faster than YAML parsers. For a 100KB document,
Node's built-in JSON.parse typically finishes in under
1ms; the yaml npm package takes 15-40ms for the same
bytes. PyYAML's pure-Python parser is the slowest of the bunch
(libyaml-backed yaml.CSafeLoader closes the gap). For a
config file loaded once at startup, the difference is invisible. For
a wire format processing thousands of messages per second, JSON's
lead is decisive.
Predictability
JSON has one canonical interpretation. YAML has at least two
common ones (1.1 and 1.2) that disagree about whether
off means false, whether 010 is octal,
and whether unquoted NO is a country code or a
boolean. The YAML parser version matters; JSON parsers don't.
Tooling and security
Every WAF, every API gateway, every framework expects JSON in HTTP
bodies. YAML parsers have a long history of CVEs (PyYAML's old
load(), snakeyaml deserialization) that JSON parsers
don't share — JSON is a strictly smaller attack surface.
The four rules that prevent most YAML bugs
- Always quote ambiguous strings. Country codes,
version numbers, and anything that could be misread as a number,
boolean, or null.
"on": truenoton: true. - Use spaces only, never tabs. Most YAML parsers reject tabs. The error message is rarely helpful.
- Pin the YAML version. Use a parser configured for YAML 1.2 if your data has any of: country codes, boolean- looking strings, leading zeros on numbers.
- Validate before deploying. Lint the file before checking it in. CI failures two minutes after merge are an avoidable expense.
Conversion
Converting in either direction is straightforward — every YAML construct except anchors maps to a plain JSON shape. Anchors get resolved (and any aliases inlined) during conversion.
Paste your YAML on the home page and toggle to JSON to see the converted output.
Reference
- YAML 1.2.2 spec — the current standard.
- RFC 8259 — JSON, the current standard.
FAQ
Is YAML always slower to parse than JSON?
Yes — by roughly 5-50× depending on the parser and content. JSON's grammar is small enough to parse with a tight state machine; YAML's grammar covers anchors, multiple document streams, type tags, and complex scalar styles. For high-throughput wire formats, JSON wins. For human-edited config, the speed gap rarely matters.
Is every JSON file valid YAML?
YAML 1.2 was designed as a superset of JSON, so a valid JSON document is parsed correctly by a YAML 1.2 parser. The reverse isn't true — most YAML features (comments, anchors, multiline strings, etc.) aren't valid JSON.
What's the 'Norway problem'?
In YAML 1.1, the unquoted string 'NO' (Norway's country code) is parsed as the boolean false, along with 'no', 'off', and 'yes'. YAML 1.2 fixed this by recognizing only 'true' and 'false' as booleans. If your parser is on YAML 1.1 (which the original PyYAML defaulted to for years), country codes break. Quote any string that could look boolean.
Should I use YAML for an API response?
No. Use JSON for wire formats — every language has a built-in JSON parser, security tooling expects JSON, and the parse cost is negligible. YAML's value is for files humans edit (CI configs, Kubernetes manifests, Ansible playbooks).
Why does my YAML config behave differently between tools?
The two most common causes: tab vs space indentation (most parsers reject tabs), and YAML 1.1 vs 1.2 type-coercion differences (Norway problem, Yes/No booleans, octal numbers like 010). Lock the version your tool uses and quote ambiguous strings.