# YAML vs JSON: Differences, Gotchas, and When to Use Each

YAML and JSON describe the same kinds of data — maps, lists, strings, numbers, booleans, null. In fact, **every JSON document is valid YAML**, because YAML is a superset. The difference is ergonomics and a handful of YAML quirks that can turn a config file into a debugging session. Here's a practical comparison.

## The surface difference: punctuation vs whitespace

JSON uses braces, brackets, quotes, and commas. YAML uses **indentation** and dashes, drops most of the punctuation, and allows comments:

```json
{
  "name": "api",
  "replicas": 3,
  "ports": [80, 443]
}
```

```yaml
# the same data in YAML
name: api
replicas: 3
ports:
  - 80
  - 443
```

For a human editing a config file, YAML is easier to read and write. For a machine exchanging data over the wire, JSON's rigid, brace-delimited structure is easier to parse and far harder to get subtly wrong.

## What YAML adds

- **Comments** (`# like this`) — the single biggest reason config files use YAML. JSON has no comments at all.
- **Anchors and references** (`&name` / `*name`) — define a block once and reuse it, reducing repetition in large configs.
- **Multi-line strings** with `|` (preserve newlines) and `>` (fold into spaces) — much nicer than JSON's `\n`-laden one-liners.
- **Less visual noise** — no trailing-comma errors, no quote-everything requirement.

## YAML's sharp edges

This is where YAML's "helpfulness" becomes a liability. Because it tries to infer types from unquoted values, it guesses wrong in some famous ways:

**The Norway problem.** YAML 1.1 interprets several unquoted words as booleans:

```yaml
countries:
  - NO    # ← becomes the boolean false, not the string "NO"
  - SE
  - FR
```

`NO`, `YES`, `ON`, `OFF`, `TRUE`, `FALSE` (in various cases) can all be coerced to booleans. The country code for Norway becomes `false`. The fix is always to **quote strings that could be misread**: `"NO"`.

**Sexagesimal and leading zeros.** In YAML 1.1, `12:30` can parse as a base-60 number, and a value like `010` may be read as octal. A version string or a ZIP code like `08544` can lose its leading zero or change value entirely. Quote them.

**Significant whitespace.** A single misaligned space changes the structure, and tabs are forbidden for indentation. The error messages are often unhelpful about *where* the indentation went wrong.

JSON has none of these ambiguities: a string is a string because it's in quotes, and there's exactly one way to write it.

## A quick comparison

| | JSON | YAML |
|---|---|---|
| Comments | no | yes |
| Syntax | braces & commas | indentation |
| Type coercion surprises | none | yes (Norway, octal, dates) |
| Multi-line strings | escaped `\n` | `|` and `>` blocks |
| Reuse (anchors) | no | yes |
| Best for | APIs, data interchange | human-edited config |
| Parsing strictness | strict, simple | lenient, complex |

## When to use which

- **JSON** for anything a program produces and consumes: API payloads, logs, data files, message queues. Predictable, universal, no surprises.
- **YAML** for files **humans edit**: CI pipelines, Kubernetes manifests, app config. The comments and readability pay off — just quote ambiguous values.

A common workflow is authoring config in YAML but needing JSON for a tool that only speaks JSON (or vice versa). The [YAML ↔ JSON converter](/tools/json/yaml-json-converter) does the round-trip in your browser; for a quick one-direction conversion you can go straight to [YAML → JSON](/convert/yaml-to-json) or [JSON → YAML](/convert/json-to-yaml).

## Takeaways

- Every JSON doc is valid YAML; YAML adds comments, anchors, and readability.
- YAML's type inference causes real bugs — **quote** any string that could look like a boolean, number, or date (the Norway problem).
- Use **JSON for machines**, **YAML for humans**, and convert between them when a tool forces your hand.
