Articles

JSON vs YAML: Which Format Should You Use?

JSON and YAML represent the same data — the difference is syntax, strictness, and footguns. Where each format wins, and which to pick for configs and APIs.

The Lycoris Team The Lycoris Team · · 5 min read
Code braces linking API endpoints

JSON and YAML describe the same kinds of data — objects, lists, strings, numbers, booleans, and null — so choosing between them is never about expressive power. It’s about ergonomics and safety. JSON is strict, compact, and universally parseable; YAML is looser and easier for humans to read and edit. The short answer: use JSON for data that programs exchange, use YAML for configuration that people maintain, and let your ecosystem’s conventions override either default.

The same data, two syntaxes

Here is one service configuration written both ways. First in JSON:

{
  "service": "checkout",
  "replicas": 3,
  "debug": false,
  "regions": ["us-east", "eu-west"],
  "limits": { "cpu": "500m", "memory": "256Mi" }
}

And the identical structure in YAML:

# Scale replicas up before the holiday rush
service: checkout
replicas: 3
debug: false
regions:
  - us-east
  - eu-west
limits:
  cpu: 500m
  memory: 256Mi

Both parse into the same object in memory. The YAML version drops the braces, brackets, quotes, and commas, expresses nesting through indentation — and, notably, carries a comment, which JSON cannot do at all.

Where YAML shines

Comments. Configuration wants explanation: why a timeout is 60 seconds, when a flag can be removed. YAML supports # comments anywhere; JSON has no comment syntax, which is a constant irritation in config files.

Readability. For deeply nested structures, indentation reads more naturally than counting braces. Quotes are optional for most strings, and long text can be written as readable multi-line blocks with | or >.

Reuse. YAML anchors let you define a block once and merge it elsewhere:

defaults: &defaults
  retries: 3
  timeout: 30

production:
  <<: *defaults
  timeout: 60

Multiple documents. A single YAML file can hold several documents separated by --- — which is why one Kubernetes manifest file can define a Deployment and a Service together.

YAML’s footguns

The flexibility has real costs.

Significant whitespace. Indentation is the structure. One wrong space silently changes what a key belongs to, and the file often still parses — into the wrong shape. JSON fails loudly on a syntax error; YAML frequently fails quietly.

Implicit typing. Classic YAML guesses types from unquoted values, which produces the famous Norway problem: in a list of country codes, country: NO parses as boolean false. Likewise version: 1.10 becomes the number 1.1. YAML 1.2 removed most of these coercions, but widely used parsers still default to the older behavior, so the defensive habit is to quote anything ambiguous.

Spec complexity. The JSON grammar fits on a page. The YAML spec is enormous — tags, anchors, flow styles, multiple string block modes — and different parsers implement different subsets, so the same file can behave differently across languages.

Deserialization risk. YAML’s tag system can instruct a parser to construct native objects, not just plain data. Older defaults made this dangerous: Python’s yaml.load would happily instantiate arbitrary classes from untrusted input, and a famous 2013 Rails vulnerability turned YAML parsing into remote code execution. Modern libraries default to safe loading, but the rule stands — parse untrusted YAML with the safe API (yaml.safe_load and equivalents), and never feed user-supplied YAML to a full-featured loader. JSON parsers, by contrast, can only ever produce plain data, which is exactly why JSON is the safer choice at trust boundaries.

Where JSON shines

Strictness. There is exactly one way to write most values, and malformed input is rejected immediately. That predictability is why JSON is the default for machine-to-machine exchange.

Ubiquity and speed. Every browser parses JSON natively with JSON.parse(), every language ships a battle-tested parser, and parsing is significantly faster than YAML — which matters when an API serializes thousands of payloads per second.

No surprises. All strings are quoted and all types are explicit. Nothing is coerced, so "NO" is always the string "NO".

The gaps are the mirror image of YAML’s strengths: no comments, no trailing commas, and verbose syntax for humans to hand-edit. Variants like JSONC and JSON5 patch this for editor config files (VS Code settings, for example), but they are extensions, not standard JSON.

YAML is a superset of JSON

A useful and underused fact: any valid JSON document is also valid YAML 1.2. You can paste a JSON object straight into a YAML file — or write one section of a YAML config in JSON flow style when the inline form is clearer — and a YAML parser accepts it. The reverse is not true: YAML’s comments, anchors, and unquoted strings have no JSON equivalent.

This also means tooling built for JSON data often applies to YAML: since both parse to the same structures, a JSON Schema can validate a YAML config just as well as a JSON payload.

Side by side

JSONYAML
CommentsNot supported# anywhere
Syntax errorsLoud, immediateOften silent (indentation)
TypingExplicit, always quoted stringsImplicit by default
Parse speedFast, native in browsersSlower, needs a library
Spec sizeOne pageLarge, parser behavior varies
ReuseNoneAnchors and merge keys
Best forAPIs, data interchangeHuman-edited configuration

In practice, the ecosystem decides

Most of the time you don’t actually choose. REST APIs speak JSON, full stop. Kubernetes manifests, Docker Compose files (see Docker for beginners), and GitHub Actions workflows are YAML, full stop. package.json and tsconfig.json are JSON because Node and TypeScript said so.

Where you do get a choice — a config file for your own tool, say — the question to ask is who edits this and how often. Edited by humans, reviewed in pull requests, full of decisions worth annotating: YAML (or TOML, which Rust’s Cargo and Python’s pyproject.toml chose for its flatter, less error-prone syntax). Generated and consumed by machines: JSON.

The takeaway

JSON and YAML encode the same data; they optimize for different readers. JSON’s strictness makes it the right format for anything programs exchange — APIs, serialized state, generated config. YAML’s comments and clean syntax make it the right format for anything humans maintain — deployment manifests, CI pipelines, application settings — as long as you respect its footguns: quote ambiguous values, mind your indentation, and validate the result with a schema. When the ecosystem has already picked a format for you, that convention beats either default.

The Lycoris Team The Lycoris Team · · 5 min read

What Is JSON Schema? JSON Validation, Explained

JSON Schema is a vocabulary for describing and validating the shape of JSON data. How schemas work, where they show up, and the keywords that matter.

#JSON #Web Development #Developer Tools
The Lycoris Team The Lycoris Team · · 6 min read

What Is JSON? The Data Format That Runs the Web

JSON is a lightweight text format for structured data — the default for APIs and config files. Syntax, examples, common mistakes, and why it beat XML.

#JSON #Web Development #Developer Tools
Takina Takina · · 4 min read

What Is a Lockfile? Reproducible Dependency Installs

A lockfile records the exact dependency versions your package manager resolved, so every install — from your laptop to CI — reproduces the same tree.

#JavaScript #Web Development #Developer Tools