Comprehensive Guide to TOML¶
What It Is¶
TOML (Tom's Obvious, Minimal Language, created by Tom Preston-Werner, co-founder of GitHub) is a config-file format designed to be easy for humans to read and write, and to map unambiguously to a hash table when parsed. It sits between JSON's strictness and YAML's flexibility — closer in spirit to an INI file, but with real, well-defined types and no ambiguity about nesting.
It's the format behind Rust's Cargo.toml, Python's pyproject.toml (the modern standard for Python packaging metadata), and a number of other tool configs (Hugo's config.toml, some parts of GitLab CI tooling).
Spec: toml.io.
Core Syntax¶
Key-value pairs¶
name = "Andrew"
active = true
count = 42
ratio = 3.14
Bare keys can use letters, digits, underscores, and hyphens without quoting. Keys with other characters (spaces, dots meant literally) need quoting: "my key" = "value".
Tables (sections)¶
[server]
host = "localhost"
port = 8080
[server.tls]
enabled = true
cert_path = "/etc/certs/server.pem"
[server.tls] is a dotted table name — equivalent to nesting tls as an object inside server. You don't need to declare [server] before [server.tls] explicitly appears, though doing so for readability is common.
Arrays¶
tools = ["terraform", "kubernetes", "elasticsearch"]
mixed_ok = [1, 2, 3]
Arrays can span multiple lines and even mix whitespace/comments per element:
tools = [
"terraform", # IaC
"kubernetes", # orchestration
"elasticsearch",
]
A trailing comma is allowed in multi-line arrays.
Array of tables¶
This is TOML's answer to "a list of objects," and the one construct that looks genuinely different from JSON/YAML:
[[servers]]
name = "web1"
ip = "10.0.0.1"
[[servers]]
name = "web2"
ip = "10.0.0.2"
Each [[servers]] header appends a new table to the servers array. This parses equivalently to the JSON:
{ "servers": [
{ "name": "web1", "ip": "10.0.0.1" },
{ "name": "web2", "ip": "10.0.0.2" }
]}
Inline tables¶
For small, single-line objects:
point = { x = 1, y = 2 }
Note: unlike multi-line tables, inline tables must be written on a single line per the spec (though not all parsers strictly enforce this).
Strings¶
basic = "A string with \"escapes\" and \n newlines"
literal = 'No escapes here, what you see is what you get \n'
multiline_basic = """
Line one.
Line two.
"""
multiline_literal = '''
Raw text, no escape processing.
'''
Numbers¶
int_val = 42
negative = -17
float_val = 3.14
exponent = 5e+22
hex_val = 0xDEADBEEF
octal_val = 0o755
binary_val = 0b11010110
underscored = 1_000_000 # underscores allowed for readability
Dates and times — a native type¶
Unlike JSON and YAML, which treat dates as plain strings, TOML has first-class date/time types conforming to RFC 3339:
offset_datetime = 2026-08-25T14:30:00Z
local_datetime = 2026-08-25T14:30:00
local_date = 2026-08-25
local_time = 14:30:00
A conforming parser hands these back as actual date/time objects, not strings — no manual parsing required on the consuming end.
Comments¶
# This is a comment, running to end of line
name = "Andrew" # inline comments work too
Gotchas¶
- Dotted keys vs. explicit tables express the same nesting two different ways, which can make a hand-edited file look inconsistent:
toml a.b.c = 1 # is equivalent to: [a.b] c = 1 - Array-of-tables (
[[x]]) is the one construct that trips up newcomers — it's easy to confuse[x](a single table) with[[x]](appending to an array of tables), and mixing the two for the same key is invalid. - Once a table is "closed" by a later table header, you can't reopen it out of order — all keys for
[server]must appear together (or under further-nested[server.x]headers) before the next top-level table begins; TOML doesn't allow scattering a table's keys across the file. - Redefining a key is an error, unlike some looser formats that silently take the last value — a conforming TOML parser should reject it outright.
- Tooling support is thinner than JSON or YAML outside the Rust/Python packaging ecosystems — fewer linters, less universal editor support, though this has been improving steadily.
Comparison to JSON/YAML at a Glance¶
| TOML | YAML | JSON | |
|---|---|---|---|
| Comments | Yes | Yes | No |
| Native dates | Yes | No | No |
| Nesting via | Table headers / dotted keys | Indentation | Braces |
| List-of-objects | [[table]] |
- block sequence |
[{}, {}] |
| Ambiguity | Low | Higher (type coercion surprises) | None |
Tools¶
- toml.io — spec and reference, including a side-by-side comparison with JSON
- Taplo — TOML linter, formatter, and language server (powers TOML support in
rust-analyzer-adjacent tooling and several editors) - Native/standard-library support: Rust's
tomlcrate (used throughout the Cargo ecosystem), Python'stomllib(built into the standard library since Python 3.11, read-only;tomli/tomli_wfor older versions or writing) - Cargo.toml reference — a good real-world example of TOML's array-of-tables and nested-table conventions in active use