YAML vs JSON vs TOML for Config Files: Syntax Table
Quick answer
JSON is the interchange format: strict, no comments, universally parsed. YAML is the human-edited format for deeply nested documents (Compose, Kubernetes, CI) and, per the YAML 1.2 spec, a strict superset of JSON. TOML is the flat-tables format with unambiguous types and native dates, used by pyproject.toml and Cargo.toml. Pick the one your ecosystem already reads; the syntax differences below are what you will actually hit.
The same config in all three formats
A service config with a name, port, boolean, list of hosts, nested database section, and a release timestamp. The JSON and YAML samples were parsed with Node (js-yaml 4.1.1) and Python (json, PyYAML 5.4.1); the TOML sample was checked line by line against the TOML v1.0.0 specification.
JSON
{
"name": "api-gateway",
"port": 8080,
"debug": false,
"hosts": ["10.0.0.1", "10.0.0.2"],
"database": {
"url": "postgres://db:5432/app",
"pool_size": 10
},
"released": "2026-09-17T10:00:00Z"
}YAML
# Server settings
name: api-gateway
port: 8080
debug: false
hosts:
- 10.0.0.1
- 10.0.0.2
database:
url: postgres://db:5432/app
pool_size: 10
released: 2026-09-17T10:00:00ZTOML
# Server settings
name = "api-gateway"
port = 8080
debug = false
hosts = ["10.0.0.1", "10.0.0.2"]
released = 2026-09-17T10:00:00Z
[database]
url = "postgres://db:5432/app"
pool_size = 10One difference is visible immediately: in TOML, released must come before the [database] header, because every key after a table header belongs to that table. In JSON and YAML, order inside an object is free.
What each parser returns (tested)
Types are where the three formats diverge most. The date is a plain string in JSON but a real date object in YAML and TOML parsers:
// node yaml-test.js
const yaml = require('js-yaml')
const j = JSON.parse(fs.readFileSync('config.json', 'utf8'))
const y = yaml.load(fs.readFileSync('config.yaml', 'utf8'))
console.log(typeof j.released) // string
console.log(y.released instanceof Date) // true -> 2026-09-17T10:00:00.000Z
console.log(JSON.stringify(yaml.load(fs.readFileSync('config.json', 'utf8'))) === JSON.stringify(j))
// true -> the JSON file is also valid YAML# python3
import json, yaml
j = json.load(open('config.json'))
y = yaml.safe_load(open('config.yaml'))
print(type(j['released']).__name__) # str
print(type(y['released']).__name__) # datetime -> 2026-09-17 10:00:00+00:00Per the Python docs, tomllib (3.11+) maps a TOML offset date-time to a timezone-aware datetime.datetime, a table to dict, and an array to list. It is read-only: there is no tomllib.dumps.
Syntax comparison table
| Feature | JSON | YAML | TOML |
|---|---|---|---|
| Comments | None (RFC 8259) | # line comment | # line comment |
| Nesting | Braces, any depth | Indentation (spaces only) | [table] and [a.b.c] headers; inline { } tables |
| Lists | [1, 2] | - item per line, or [1, 2] | [1, 2] ; [[name]] for arrays of tables |
| Strings | Always double-quoted | Unquoted, 'single', or "double" | "basic" (escapes) or 'literal' (no escapes) |
| Multi-line strings | Only with \n escapes | | keeps newlines, > folds them | """basic""" or '''literal''' |
| Dates | Strings only | Timestamp scalars (parser-dependent) | Native RFC 3339 date-times, dates, times |
| Trailing commas | Not allowed | Not applicable | Allowed in arrays, not in inline tables |
| Booleans | true / false | true / false (YAML 1.1 also yes/no/on/off) | true / false only |
| Superset relation | Subset of YAML 1.2 | Designed as a strict superset of JSON (1.2) | Independent format |
| Schema / tooling | JSON Schema, ubiquitous | JSON Schema via YAML editors, linters | Taplo, schema stores; fewer editors |
| Typical files | package.json, tsconfig.json, API bodies | docker-compose.yml, Kubernetes, GitHub Actions | pyproject.toml, Cargo.toml, Hugo config |
The YAML gotcha that TOML and JSON do not have
YAML guesses scalar types, and the guess depends on the parser's YAML version. The same three lines, run through PyYAML 5.4.1 (YAML 1.1 rules) and js-yaml 4 (YAML 1.2 rules):
country: NO # PyYAML -> False js-yaml -> 'NO'
version: 1.10 # PyYAML -> 1.1 js-yaml -> 1.1 (both: float)
time: 12:30 # PyYAML -> 750 js-yaml -> '12:30'Quote anything that could look like a boolean, number, or time. JSON has no such ambiguity because every string is quoted, and TOML has none because its strings must be quoted and its dates follow RFC 3339.
Decision rule
- ▸Machine-to-machine or a tool already mandates it (package.json, API payloads, lockfiles): JSON.
- ▸Deep nesting edited by people (Compose services, Kubernetes manifests, CI workflows): YAML, with ambiguous scalars quoted.
- ▸Mostly flat sections with typed values and dates (project metadata, tool settings): TOML.
Primary sources: TOML v1.0.0 spec, YAML 1.2.2 spec, RFC 8259 (JSON), Python tomllib.
Frequently Asked Questions
Is YAML a superset of JSON?
By design, yes. The YAML 1.2 specification states that its primary focus was making YAML a strict superset of JSON, so a valid JSON document is also a valid YAML 1.2 document. In practice, older YAML 1.1 parsers (for example PyYAML) still differ on a few scalars such as unquoted NO or 12:30, so quote ambiguous strings.
Does JSON support comments?
No. RFC 8259 JSON has no comment syntax. YAML and TOML both use # for line comments. If you need comments in a JSON-shaped config, use YAML, TOML, or a JSON-with-comments dialect that your specific tool accepts (for example tsconfig.json), not plain JSON.
Which format should I pick for a new config file?
JSON when the file is written or read by programs and interoperability matters (package.json, API payloads). YAML when humans edit deeply nested documents and the ecosystem already uses it (Docker Compose, Kubernetes, GitHub Actions). TOML when the config is mostly flat key/value tables and you want unambiguous types and native dates (pyproject.toml, Cargo.toml).
Can Python read TOML without installing a package?
Yes, from Python 3.11 onward: the standard-library tomllib module parses TOML 1.0.0 with tomllib.load() and tomllib.loads(). It is read-only, so writing TOML still needs a third-party package. On Python 3.10 and older, tomllib does not exist.
Try it in the browser
- YAML Validator, catch indentation and type-guessing problems before deploy.
- JSON to YAML Converter, convert the JSON sample above and compare.
- JSON Formatter, validate and pretty-print JSON config.