---
title: TOML vs YAML: Config Formats Compared | Relic
description: TOML vs YAML for configuration: design goals, the same config in both, YAML's Norway problem and implicit typing, TOML's limits, and where each format won.
canonical: https://relic.space/blog/toml-vs-yaml
source: https://relic.space/llms.txt
---
[Developer cheat sheets](https://relic.space/blog/topics/dev-reference)

# TOML vs YAML

TOML and YAML both describe configuration in plain text, but they were designed for different jobs. TOML aims to be obvious and minimal. YAML aims to serialize any data structure a human can read. That difference explains where each one won, and where YAML's famous sharp edges come from.

[JGJordan Gibbs](https://relic.space/authors/jordan-gibbs) July 10, 2026 6 min readUpdated September 12, 2026

## What is the difference between TOML and YAML?

TOML is a minimal config format that maps to a hash table, with explicit headers like \[database\]. YAML is a data serialization language that uses indentation and handles deep nesting. Use TOML for shallow config a person edits by hand. Use YAML for nested manifests and pipelines, quoting any value that could be misread.

If you have edited a [**pyproject.toml**](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/) and a Kubernetes manifest in the same week, you have used both. TOML (Tom’s Obvious, Minimal Language) and YAML (YAML Ain’t Markup Language) overlap enough that people ask which to pick, but they were built with different goals, and matching the format to the goal settles most arguments.

## Design goals

* **TOML** was [designed to be an obvious, minimal config format that maps cleanly to a hash table](https://toml.io/en/v1.0.0). The priority is that a human can read it at a glance and rarely be surprised by how a value parses.
* **YAML** was designed as a human-friendly data serialization language. It can represent arbitrary nested data, references, and multiple documents in one file, which makes it powerful and also gives it more ways to trip you up.

## The same config in both

Here is a small service config written in TOML.

config.toml

title = "My Service"
port = 8080
debug = false

[database]
host = "localhost"
port = 5432
name = "app"

[[server]]
region = "us-east"
weight = 10

[[server]]
region = "eu-west"
weight = 5

And the same thing in YAML.

config.yaml

title: My Service
port: 8080
debug: false

database:
  host: localhost
  port: 5432
  name: app

server:
  - region: us-east
    weight: 10
  - region: eu-west
    weight: 5

Notice the trade already. TOML makes structure explicit with headers like \[database\] and \[\[server\]\], which reads clearly but gets verbose as nesting deepens. YAML uses indentation, which is compact for nested data but means whitespace is now load-bearing.

## What goes wrong with YAML?

YAML is genuinely pleasant for nested data, but it has a few traps that bite real projects. These are not folklore; they come from the spec and from parsers that never moved past an older version of it.

### The Norway problem (implicit typing)

Under [YAML 1.1](https://yaml.org/type/bool.html), several unquoted words become booleans: **yes**, **no**, **on**, **off**, **true**, **false**. The classic bug is a list of country codes where **NO** (Norway) is silently read as the boolean false. [YAML 1.2](https://yaml.org/spec/1.2.2/) fixed this by limiting booleans to true and false, but many widely used parsers kept the 1.1 behavior, so the problem is still out there. The defence is simple: quote any string that could be mistaken for another type.

Quote to be safe in YAML

countries:
  - "NO"
  - "SE"
  - "DK"
version: "1.10"

That version line matters too. Unquoted, 1.10 can be read as a number and lose its trailing zero, becoming 1.1.

### Indentation and implicit typing in general

* Whitespace defines structure, so a stray space or a tab where spaces are expected changes the meaning or fails the parse. Tabs for indentation are not allowed at all.
* Implicit typing goes beyond booleans. A value that looks like a number, a date, or null gets coerced unless you quote it, which is how a ZIP code or a Git SHA can lose leading zeros or change type.

A blunt way to stay safe in YAML: when in doubt, quote the value. Strings that could be read as booleans, numbers, dates, or null are exactly the ones that cause silent bugs, and quoting them costs nothing.

## What are TOML’s downsides?

TOML is not free of trade-offs either. Its strengths fade as data gets deeply nested.

* **Deep nesting gets noisy.** Every level of nesting wants its own \[section.subsection\] header, and once you are three or four levels down, the headers repeat and the file gets long.
* **Arrays of tables read oddly at first.** The \[\[server\]\] double-bracket syntax for a list of objects is unusual until you have seen it a few times, and it is easy to confuse with a single \[server\] table.

For flat or moderately nested config, none of this bites. TOML stays readable precisely because it refuses to be clever, which is the whole point of the format.

## Where each one won

|      | Format                                 | Wins for                                                                  | Because |
| ---- | -------------------------------------- | ------------------------------------------------------------------------- | ------- |
| TOML | pyproject.toml, Cargo.toml             | Flat-to-moderate config that a person edits by hand; minimal surprises    |         |
| YAML | Kubernetes, CI configs, Docker Compose | Deeply nested data and lists where indentation reads cleaner than headers |         |
| JSON | Data between programs, APIs            | Strict, unambiguous types every language parses the same way              |         |

The ecosystems reflect this. [Rust](https://doc.rust-lang.org/cargo/reference/manifest.html) and modern Python packaging standardized on TOML because the config is human-edited and mostly shallow. The cloud-native world runs on YAML because manifests and pipelines are deeply nested and change often. Neither community picked wrong; they picked for the shape of their data.

## Should you use JSON instead?

When a format is read by programs more than people, **JSON** is often the right answer. Its type rules are strict, every language parses it identically, and there is no implicit typing to surprise you. The costs are that it has no comments and is fussy about trailing commas, which makes it a poor format for config a human maintains. A common split is JSON on the wire and TOML or YAML for the file someone edits. If you are staring at a wall of unformatted JSON, our [JSON formatter](https://relic.space/tools/json-formatter) will indent and validate it in your browser.

## Which one should you use?

Match the format to the data. Shallow, hand-edited config: TOML. Deeply nested manifests and pipelines: YAML, with values quoted whenever they could be misread. Machine-to-machine data: JSON. For more references cut the same way, the [regex cheat sheet](https://relic.space/blog/regex-cheat-sheet) and the rest of our [developer cheat sheets](https://relic.space/blog/topics/dev-reference) keep the syntax you half-remember close at hand.

## Sources

* [TOML v1.0.0](https://toml.io/en/v1.0.0), toml.io
* [YAML Ain't Markup Language (YAML) revision 1.2.2](https://yaml.org/spec/1.2.2/), yaml.org
* [The Manifest Format](https://doc.rust-lang.org/cargo/reference/manifest.html), The Cargo Book
* [Writing your pyproject.toml](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/), Python Packaging User Guide

## Frequently asked questions

Is TOML or YAML better for configuration?+

It depends on the shape of the data. TOML is built to be an obvious, minimal config format, so it wins for flat-to-moderate settings like pyproject.toml or Cargo.toml. YAML is a general data serialization format that handles deep nesting and lists more gracefully, which is why Kubernetes manifests, CI pipelines, and Docker Compose files use it. If your config is shallow, TOML is easier to read and harder to break. If it is deeply nested, YAML reads better.

What is the Norway problem in YAML?+

In YAML 1.1, unquoted values like no, yes, on, and off are parsed as booleans. So a list of country codes that includes NO for Norway can turn into the boolean false. YAML 1.2 fixed this by restricting booleans to true and false, but many popular parsers still follow 1.1 behavior, so the trap persists in practice. The fix is to quote strings that could be misread as another type.

Should I use JSON instead of TOML or YAML?+

JSON is the safest choice for data exchanged between programs, because its type rules are strict and unambiguous and every language can parse it. It is a poor config format for humans because it has no comments and is picky about trailing commas. Many teams use JSON on the wire and TOML or YAML for the config a person edits by hand.

JG

Written by

[Jordan Gibbs](https://relic.space/authors/jordan-gibbs)Founder, Relic

Jordan Gibbs is the founder of Relic, an end-to-end encrypted, permanent, searchable memory for everything you copy. He writes widely about AI, agents, and practical tooling on Medium, where he is read by tens of thousands, and builds privacy-first software. Here he covers how everyday tools like the clipboard actually work, and how to use them without handing your data to someone else.

[Medium](https://medium.com/@jordan%5Fgibbs)[GitHub](https://github.com/jordan-gibbs)[LinkedIn](https://www.linkedin.com/in/jordan--gibbs/)

Part of

[Developer cheat sheets](https://relic.space/blog/topics/dev-reference)
* [Regex cheat sheet· pillar](https://relic.space/blog/regex-cheat-sheet)
* [How to copy and paste in Vim](https://relic.space/blog/how-to-copy-and-paste-in-vim)
* [How to copy to the clipboard from the command line](https://relic.space/blog/copy-to-clipboard-from-the-command-line)
* [What AI crawlers fetch from a small open-source site: 31 days of logs](https://relic.space/blog/ai-crawlers-on-a-small-site)
* [JSONPath examples](https://relic.space/blog/jsonpath-examples)
* [jq cheat sheet](https://relic.space/blog/jq-cheat-sheet)
* [wget vs curl: what is the difference?](https://relic.space/blog/wget-vs-curl)
* [Subnet cheat sheet](https://relic.space/blog/subnet-cheat-sheet)
* [Port numbers list](https://relic.space/blog/port-numbers-list)
* [Ed25519 vs RSA](https://relic.space/blog/ed25519-vs-rsa)

Keep reading

[Pillar·10 minRegex cheat sheetThe regex pieces you actually reach for, character classes through lookarounds, with the flavor differences that bite you and a handful of patterns worth saving.Read ](https://relic.space/blog/regex-cheat-sheet)[9 minHow to copy and paste in Vimy copies and p pastes, but only inside Vim. How registers work, how to reach the system clipboard when your build says -clipboard, and how to copy out over SSH and in tmux.Read ](https://relic.space/blog/how-to-copy-and-paste-in-vim)[8 minHow to copy to the clipboard from the command linePipe any command into the clipboard on Mac, Linux, Windows and WSL. The commands for each, plus the newline and encoding problems that break pasted text.Read ](https://relic.space/blog/copy-to-clipboard-from-the-command-line)

developerreferenceconfiguration
