TOML vs YAML for Configuration Files

TOML and YAML are both designed to be written by people, and both show up in nearly every modern toolchain. They make opposite trade-offs: TOML is explicit and flat, YAML is concise and deeply nestable. Here is how to decide.

Two philosophies

TOML (“Tom’s Obvious, Minimal Language”, version 1.0.0 released in 2021) looks like an INI file with a real type system. Sections are written as [table] headers, every string is quoted, and the specification is short enough to read in one sitting. It is the configuration format of Rust’s Cargo, Python’s pyproject.toml, Hugo, Netlify, and tools such as Ruff and uv.

YAML expresses structure through indentation and leaves quotes optional. It shines for deeply nested data and long lists of objects, which is why Kubernetes, Docker Compose, GitHub Actions, GitLab CI, Ansible and OpenAPI documents use it.

The same small configuration in each:

# server settings
[server]
host = "0.0.0.0"
port = 8080

[database]
url = "postgres://localhost/shop"
pool = 10
# server settings
server:
  host: 0.0.0.0
  port: 8080
database:
  url: postgres://localhost/shop
  pool: 10

Feature comparison

  • Typing: TOML types are explicit. Strings must be quoted, so "NO" can never become a boolean and "3.10" never becomes 3.1. YAML infers types from unquoted values, with different rules in 1.1 and 1.2.
  • Dates and times: TOML has four first-class date/time types — offset date-time (1979-05-27T07:32:00Z), local date-time, local date and local time. YAML 1.1 has an optional timestamp type that many parsers apply, YAML 1.2’s core schema has none.
  • Null: TOML has no null. A key is either present with a value or absent. YAML has null and ~, and an empty value is null.
  • Integers: TOML allows 1_000_000 digit separators and 0x, 0o, 0b prefixes. YAML 1.2 supports 0x and 0o.
  • Nesting: YAML nests by indentation to any depth. TOML uses dotted headers such as [tool.ruff.lint] and dotted keys, which stays readable for two or three levels and becomes noisy beyond that.
  • Lists of objects: TOML writes them as repeated [[array.of.tables]] blocks. YAML writes them as a - list of maps, which is much more compact for things like container definitions.
  • Reuse: YAML has anchors and aliases; TOML has no reuse mechanism.
  • Whitespace: indentation in TOML is cosmetic. In YAML it is the structure, so a mis-indented line silently changes meaning.
  • Comments: both use #.
  • Multiple documents: YAML supports several documents in one file; TOML does not.

Where TOML is the better choice

Choose TOML for configuration that is mostly flat — a handful of sections with scalar settings — and that people edit by hand without schema-aware tooling. The explicit typing removes a whole class of bugs, and the grammar is small enough that independent parsers in different languages agree with each other, which is not always true for YAML.

TOML also enforces some sanity rules that YAML leaves to the parser. Defining the same key or the same [table] twice is an error, not a silent overwrite. If you have ever debugged a YAML file where a duplicated key quietly replaced an earlier one, this is a real advantage.

[package]
name = "pastekit-core"
version = "0.1.0"
edition = "2021"

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

[[bin]]
name = "pp"
path = "src/main.rs"

Inline tables like the serde line keep short nested values on one line; in TOML 1.0 they must fit on a single line and cannot end with a trailing comma.

Where YAML is the better choice

Choose YAML when the data is a deep tree or a long list of similar records, when the ecosystem already expects it (Kubernetes and CI systems), or when you need anchors to avoid repeating blocks. Writing a Kubernetes Deployment in TOML would technically work but would be painful to read, because every container, port and environment variable would need its own [[...]] header.

If you do choose YAML, protect yourself from its implicit typing: quote values that look like booleans, numbers or dates but are meant as strings, use a formatter to keep indentation consistent, and validate the file against a JSON Schema where one exists. The YAML formatter reports duplicate keys and tab indentation as errors with line numbers.

Mistakes people make in TOML

TOML’s strictness shows up as errors rather than surprises, and a handful account for most of them:

  • Defining a table twice. Writing [server] in two places is invalid, even if the keys differ. Merge the two blocks.
  • Mixing dotted keys and headers for the same table. After server.port = 80 at the top level, a later [server] header redefines a table that already exists.
  • Extending an inline table. db = { host = "x" } is complete; adding db.port = 5432 later is an error. Use a [db] section if the table will grow.
  • Unquoted strings. env = production is invalid; strings always need quotes.
  • Keys after an array-of-tables header. Everything after [[bin]] belongs to that array element until the next header, a common reason for keys ending up in the wrong place.

Converting and tooling

Both formats map onto the same data model as JSON, with two catches. TOML cannot represent null, so a YAML-to-TOML conversion must drop or replace null values, and TOML requires the document root to be a table, so a top-level YAML list cannot be converted directly. Comments are lost in any conversion that goes through a parsed data structure.

PasteKit converts in both directions in the browser: YAML to TOML, TOML to YAML and TOML to JSON. The TOML formatter uses taplo for layout and validates with a spec-compliant parser, so it catches a table defined twice before Cargo or pip does.

Editor support is good for both: the Even Better TOML extension (built on taplo) and the Red Hat YAML extension both validate against JSON Schemas from the SchemaStore catalogue.

Frequently asked questions

Is TOML better than YAML?

For flat, hand-edited configuration, TOML is usually safer because types are explicit. For deeply nested data or long lists of objects, YAML is more readable.

Why does TOML have no null?

TOML treats a missing key as the way to say “no value”. This keeps the format simple but means converters must drop null values when going from JSON or YAML.

Can TOML represent everything YAML can?

Not quite. TOML has no null, no anchors and aliases, no multi-document files, and its root must be a table rather than a list.

Which format does Python use for project configuration?

pyproject.toml, standardised by PEP 518 and PEP 621. Most Python tools, including pytest, Ruff, Black and uv, read their settings from it.

Related