Skip to content
datahacks.dev
YAML

YAML Versus JSON for Configuration Files That Last

Comments, types, size, parse speed and safety compared with measured numbers, plus why JSON is nearly valid YAML. One format costs 55 times more to parse.

6 min read
Summarize in AI
Flat illustration of two options weighed side by side, with the YAML and JSON logos.

For configuration files the decision usually comes down to two formats, and teams argue about it as if one of them were correct. They are both fine. They fail in different ways, and the question is which failure you would rather have. JSON is strict and has no comments. YAML is expressive and sometimes too clever. This post compares them on the properties that matter for a file that people maintain for years: readability, comments, types, safety and cost, with measurements where they exist.

The same file in both

Five settings: a server, a list of features, a country code and a timeout.

JSON
{"server":{"host":"db1","port":5432},"features":["search","export"],"country":"NO","timeout":30}
YAML
# comment survives in the file
server: {host: db1, port: 5432}
features: [search, export]
country: NO
timeout: 30

Sizes: 96 bytes as JSON, 114 as YAML (with the comment line). In real files the YAML is usually shorter than pretty-printed JSON, because it has no braces or quotes, and longer than minified JSON. None of it matters for configuration. What matters is the rest of the list.

Comments

YAML has them. JSON does not, and parsers enforce it:

Text
Expecting ',' delimiter: line 1 column 8 (char 7)

That is Python's json.loads rejecting {"a":1 /* c */}. For a file that people edit, the lack of comments is the strongest argument against JSON: nowhere to write "why". Variants exist (JSONC in some editors, JSON5), and each requires a reader that understands it, which means a different format that happens to look like JSON. If your readers all support one, it is a workable middle path.

JSON is almost YAML

YAML 1.2 was designed so that JSON documents are valid YAML, and the common parsers read JSON as YAML:

Text
{'a': [1, 2, {'b': None}], 'c': 'x'}

This gives you a migration path in both directions and a practical tip: when in doubt, you may write a YAML file in JSON-style flow syntax, and it will load. The exceptions are in the corners (duplicate keys, some escape sequences, very long keys), and for ordinary documents it holds (YAML lists and mappings without confusion shows the forms side by side). The reverse is not true: most YAML is not JSON.

Types and surprises

JSON has a small, fixed set of types and no guessing: a string is quoted, a number is not, true, false and null are the only literals. YAML guesses. Whether the guess is right depends on the version of the language the parser implements:

Text
countries: [GB, FR, NO, SE]   ->   PyYAML: ['GB', 'FR', False, 'SE']
ports: [22:22, 80:80]         ->   PyYAML: [1342, '80:80']
version: 3.10                 ->   3.1

The Norway problem, a port mapping that looked like a base-60 number and a version that lost its zero are all YAML 1.1 behaviors (the Norway problem and YAML boolean surprises, YAML 1.1 versus 1.2). YAML 1.2 parsers avoid most of them, and you rarely control every reader. JSON has no such risk: if you write "NO", it is a string everywhere. For files whose values are mostly strings and codes, the strictness is a feature.

Cost

Parsing speed is irrelevant for a ten-line config and decisive for bulk data. On 50,000 generated orders (about 11 MB), Python's json took 132 ms, and PyYAML's C loader took 7,238 ms, 55 times as long. The YAML grammar is much larger and the loader builds events and nodes before constructing objects. That is why YAML is a configuration format and not a data format: do not put a million records in it. XML (lxml) parsed the same data in 161 ms, for comparison (XML versus Protocol Buffers for services has the full table).

Safety

Two safety points. First, loading: PyYAML's yaml.load with the default or unsafe loader can construct arbitrary Python objects from tags, and a document with the right tag runs code during load. safe_load refuses (why yaml load is dangerous). JSON has no such mechanism, so json.loads on untrusted input is safe from this class of problem. Second, ambiguity: because YAML has several ways to write the same thing, two people can disagree about what a file means. JSON has one way.

A decision

QuestionJSONYAML
Edited by hand, oftenPoor (no comments, commas, quotes)Good
Written by programsGoodFine, but let the library write it
Needs commentsNoYes
Strings that look like other typesSafeQuote them or use a 1.2 parser
Large dataGoodPoor
Ecosystem expects itnpm, many APIsKubernetes, Compose, CI systems
ValidationJSON SchemaJSON Schema on the parsed data
Reuse of blocksNoneAnchors and merge keys

Follow the ecosystem first. A Kubernetes manifest is YAML and a package.json is JSON, and inventing the opposite costs you tooling. When you choose freely, use YAML for files people maintain and JSON for files programs exchange. If you are tempted to use YAML for application data between services, use JSON, or a binary format.

Using both in one project

Many projects end up with both formats, and a few conventions keep that peaceful. Use YAML for the files that humans edit and review, and JSON for the files that programs produce and consume, such as lock files, generated manifests and API payloads. Never hand-edit a generated JSON file, and never generate a YAML file that people are expected to edit by hand without a library that preserves their comments (preserving comments and order with ruamel yaml).

Convert at the boundary, not in the middle. If a tool needs JSON and the source of truth is YAML, convert in the build step and keep the JSON out of version control, so the two cannot drift. A one-line command does it, and the YAML to JSON tool does the same in a browser for a quick look. Add a test that loads the YAML and checks the fields the program reads, since a conversion can succeed on a file whose meaning is wrong.

When you start a new file and are undecided, start in YAML and write it with quotes around strings that could be misread. If the quoting rules annoy the team after a month, you have learned something about how your file is used, and moving to JSON with a schema is a small step because JSON is nearly valid YAML.

The cluster hub is YAML syntax you need to stop guessing at. The three-way comparison with XML is in XML versus JSON versus YAML for configuration. JSON is specified in RFC 8259 and the relationship to YAML in the YAML 1.2.2 specification, section 1.3. Convert a file in the YAML to JSON tool.

When neither YAML nor JSON is the right configuration format

The configuration is code. If it needs loops, conditionals or computed values, use a real language. Templated YAML is hard to debug.

TOML fits. For flat or lightly nested settings edited by hand, TOML has comments and explicit types and no indentation sensitivity.

The settings change at runtime. Feature flags toggled daily belong in a database or a flag service with an audit trail.

The file is large. Past a few thousand lines, split by concern, or move the data to a table format and keep only settings in YAML.

Also inJSON
Share

Keep reading

Get new articles by email

We send one email when a new article is published. No spam.

Unsubscribe in one click. No spam, ever.