If you have ever set up a CI pipeline, a Kubernetes deployment or a Rust project, you have met all three: JSON, YAML and TOML. They can describe the same nested data, so the choice can look like taste. It is not. Each format makes different trade-offs between strictness, readability and tooling, and picking the wrong one leads to subtle bugs. This guide compares JSON vs YAML vs TOML with real examples and ends with a simple rule for choosing.
The same data in JSON, YAML and TOML
Here is a small service configuration written three ways.
{
"name": "billing-api",
"port": 8080,
"debug": false,
"database": { "host": "db.internal", "pool": 10 },
"allowed_origins": ["https://example.com", "https://admin.example.com"]
}
# YAML
name: billing-api
port: 8080
debug: false
database:
host: db.internal
pool: 10
allowed_origins:
- https://example.com
- https://admin.example.com
# TOML
name = "billing-api"
port = 8080
debug = false
allowed_origins = ["https://example.com", "https://admin.example.com"]
[database]
host = "db.internal"
pool = 10
All three are readable at this size. The differences appear when files grow, when people edit them by hand and when values are ambiguous.
JSON: strict, universal, machine-first
JSON (RFC 8259) has exactly six kinds of value: objects, arrays, strings, numbers, booleans and null. Strings must use double quotes, keys must be strings, and there are no comments or trailing commas. That strictness is its strength: every mainstream language ships a JSON parser, and two parsers almost always agree on what a document means.
- Best for: API requests and responses, data exchange between services, logs (as JSON Lines), browser storage and anything generated by code.
- Weak spots: no comments, noisy punctuation for hand editing, and numbers that exceed what the reader can represent — JavaScript loses precision for integers above 253 − 1, which is why many APIs send 64-bit IDs as strings.
When a JSON file is hard to read, the problem is usually formatting rather than the format. Paste it into the JSON formatter to indent it and spot structural mistakes quickly.
YAML: readable, powerful and easy to get wrong
YAML uses indentation instead of braces, allows comments with #, and supports features JSON lacks: multi-line strings (| keeps line breaks, > folds them), several documents in one file separated by ---, and anchors and aliases (&default / *default) to reuse blocks. That is why Kubernetes manifests, GitHub Actions workflows, Docker Compose files and Ansible playbooks use it.
The same flexibility creates classic pitfalls:
- Implicit typing. Unquoted values are guessed. Under YAML 1.1 rules, still used by some popular parsers,
no,offandyesbecome booleans — the famous “Norway problem”, where the country codeNOturns intofalse. A version number such as1.10becomes the float1.1. Quote strings that only look like other types. - Indentation errors. Tabs are not allowed for indentation, and a list item indented one space too far silently changes the structure instead of failing.
- Unsafe loading. Some libraries can construct arbitrary language objects from tagged YAML. In Python use
yaml.safe_load(), neveryaml.load()on untrusted input without a safe loader.
Before committing a hand-edited file, run it through a YAML validator, or convert it with YAML to JSON to see exactly how a parser interprets every value.
TOML: explicit configuration without surprises
TOML (version 1.0.0, released in 2021) aims to be an obvious, minimal configuration format. It uses key = value pairs grouped under [tables], supports comments, and makes types explicit: strings are always quoted, integers are 64-bit, and it has first-class dates and times such as 1979-05-27T07:32:00Z. Arrays of tables ([[servers]]) express lists of objects.
- Best for: application and tool configuration that people edit by hand — Rust’s
Cargo.toml, Python’spyproject.tomland many static site generators. - Weak spots: no
null, and deeply nested data becomes verbose because every level needs a dotted key or a table header.
If you are moving settings from JSON into a TOML file, JSON to TOML handles the table layout for you; TOML to JSON goes the other way when a program expects JSON.
JSON vs YAML vs TOML at a glance
| JSON | YAML | TOML | |
|---|---|---|---|
| Comments | No | Yes (#) | Yes (#) |
| Structure | Braces and brackets | Indentation | Tables and keys |
| Null | null | null or ~ | None — omit the key |
| Dates | Strings by convention | Timestamps (parser-dependent) | Native date/time types |
| Typing | Explicit | Guessed for unquoted scalars | Explicit |
| Typical use | APIs, data exchange | Infrastructure and CI config | App and package config |
Validation and schemas
Readability is only half of maintainability; the other half is catching mistakes before they reach production. Here the three formats are closer than they look, because the same schema language covers all of them. JSON Schema describes which keys are required, what types they hold and which values are allowed. Editors such as VS Code use JSON Schema to autocomplete and validate YAML files too — that is how you get suggestions while editing a GitHub Actions workflow or a Kubernetes manifest — and TOML tooling increasingly does the same for files like pyproject.toml.
In practice this means you rarely need to choose a format for its validation story. Pick the format that suits the people editing the file, then add a schema and a CI check that parses the file and validates it. A broken configuration should fail a pull request, not a deployment.
The other practical difference is error messages. Because JSON’s grammar is tiny, parser errors are precise: the line and column usually point straight at the problem. YAML parsers can only report where the indentation stopped making sense, which may be several lines after the real mistake, and a wrongly indented block may parse successfully into the wrong structure. TOML sits in between: its explicit syntax gives clear errors, and redefining a table or key is always reported rather than silently merged.
How to choose
- Is the file written by a program and read by a program? Use JSON. Strictness and universal support beat readability.
- Is it configuration for an ecosystem that already chose? Follow the ecosystem: YAML for Kubernetes and GitHub Actions, TOML for Cargo and
pyproject.toml. Fighting convention costs more than any format advantage. - Is it your own hand-edited config? Prefer TOML for flat-to-moderate nesting and when types matter. Choose YAML when you need deep nesting, multi-line text or reusable blocks — and quote anything ambiguous.
Converting between formats safely
Conversion is lossless for plain data, but watch for features that only exist in one format:
- Comments disappear when converting YAML or TOML to JSON.
- YAML anchors are expanded into repeated copies.
nullvalues have nowhere to go in TOML.- TOML dates become strings in JSON, and YAML may turn date-like strings into timestamps.
After converting, diff the before and after data, and keep the original file under version control until the new one has been tested. JSON to YAML is a quick way to turn an API response into a readable fixture for tests.