YAML, TOML, JSON5: When Each Format Wins

By Λ · May 18, 2026 · 7 min read

JSON won the data interchange war. Nothing else is close for API payloads, log lines, and machine-to-machine messages. But JSON is a bad config file format for humans, and the industry has produced three serious challengers for that role: YAML, TOML, and JSON5. They are not interchangeable, and picking the wrong one is a real source of friction.

I have shipped projects using all three, and switched between them more than once. This essay is the decision framework I now use when picking a config format for a new project.

Why JSON is a bad config format

JSON is a great data format because it is unambiguous and machine-friendly. Those same properties make it painful to hand-edit:

All three contenders fix some of these. None fix all of them in the same way. The right choice depends on which fixes matter to you.

YAML: powerful, dangerous, ubiquitous

YAML is the most widely-used config format in 2026. Kubernetes uses it. Docker Compose uses it. GitHub Actions, GitLab CI, Ansible, and most cloud-native tooling default to YAML. If you are going to maintain other people's code, you will write YAML.

What YAML gets right:

What YAML gets wrong (and why it has a reputation for footguns):

Use YAML when: you are integrating with the cloud-native ecosystem, you need multiline strings, you have deeply nested configs, or your team is already comfortable with the gotchas.

TOML: simple, predictable, less expressive

TOML was designed explicitly as a configuration format. It is what Cargo (Rust), pip (Python), and Hugo use. The selling point: there is exactly one way to write any given config, and the syntax is unambiguous on inspection.

# Cargo.toml style
[package]
name = "my-crate"
version = "0.1.0"
authors = ["Λ <[email protected]>"]

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = "1.34"

What TOML gets right:

What TOML gets wrong:

Use TOML when: your config is mostly flat with a few nested sections, you are in the Rust or Python ecosystem, or you value predictability over expressiveness.

JSON5: JSON with the rough edges sanded off

JSON5 is JSON plus a small set of permissive extensions: comments, trailing commas, unquoted keys, single-quoted strings, and a few number-syntax additions. It compiles to JSON; any JSON5 file can be converted to JSON losslessly minus the comments.

{
  // Comments work
  databaseHost: 'localhost',     // unquoted keys, single quotes
  port: 5432,
  maxConnections: 100,           // trailing comma OK
  timeout: +Infinity,            // number syntax extensions
}

What JSON5 gets right:

What JSON5 gets wrong:

Use JSON5 when: your config is structurally JSON-shaped but you want comments, you are in an ecosystem where YAML or TOML support is patchy, or you are migrating an existing JSON config.

The decision matrix

The conversion problem

The reality is that real projects often need to convert between these. CI pipelines read YAML and emit JSON for downstream tools. A team writes config in TOML and ships JSON to a frontend. The JSON/YAML converter and TOML converter on BoltQuickTools handle these conversions in the browser without uploading anything.

Common conversion gotchas:

What I use today

For BoltQuickTools the tool manifest is in YAML because I started in a Python ecosystem and PyYAML was already a dependency. For a Rust side project I would reach for TOML. For an existing JSON config I needed to annotate, I would convert to JSON5 first and write the comments. There is no globally correct answer; the right format is the one that matches your ecosystem and your config's structure.

Related