TOML#
TOML (Tom’s Obvious Minimal Language) is
a text-based config format with a real spec. The de-facto
choice for tooling configuration in 2026: pyproject.toml,
Cargo.toml, uv.lock, poetry.lock, rustfmt.toml,
rclone.conf, and most modern CLI configs. Key/value pairs
grouped under bracketed sections; obvious mapping to a hash of
hashes; types include strings, integers, floats, booleans,
dates, arrays, and tables.
Designed to read clearly to a human and parse unambiguously by a machine. Solves the problems INI never standardised (typed values, nesting, arrays, datetimes) while staying easier to hand-edit than YAML.
Minimal example#
# comment
title = "TOML example"
[package]
name = "myscan"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
anyhow = "1"
[[bin]]
name = "scan"
path = "src/main.rs"
Types#
Every value has a type the parser determines from the literal form.
Type |
Literal |
|---|---|
string |
|
integer |
|
float |
|
boolean |
|
offset datetime |
|
local datetime |
|
local date |
|
local time |
|
array |
|
table |
|
port = 8080
timeout = 30.5
enabled = true
created = 2026-05-17T08:30:00Z
hosts = ["a.example", "b.example"]
headers = { "X-Trace" = "1", "X-Origin" = "scan" }
Tables#
A table is a key/value group. Declared with bracketed headers; nested with dotted names.
[database]
host = "127.0.0.1"
port = 5432
[database.pool]
min = 1
max = 20
[server.tls]
cert_file = "/etc/ssl/cert.pem"
key_file = "/etc/ssl/key.pem"
Equivalent inline form.
database = { host = "127.0.0.1", port = 5432,
pool = { min = 1, max = 20 } }
Inline tables must fit on one logical line and cannot be re-opened later in the file. The bracketed form is the default for anything beyond a few keys.
Arrays of tables#
Double brackets [[name]] declare an array of tables. Each
occurrence appends a new table to the array.
[[user]]
name = "alice"
roles = ["admin"]
[[user]]
name = "bob"
roles = ["reader", "writer"]
[[user]]
name = "operator"
roles = ["admin", "auditor"]
Parses to user = [{...}, {...}, {...}]. The canonical TOML
pattern for “list of records” (dependencies, bin targets,
features).
Strings#
Four forms.
Form |
When |
|---|---|
|
escape sequences ( |
|
no escapes; what you see is what you get |
|
spans lines; escapes processed |
|
spans lines; no escapes |
path = 'C:\Users\op\config' # backslashes safe
description = """
multi-line description
that spans lines.
"""
Trailing backslash on a multi-line string trims the newline that follows.
Dotted keys#
Dots inside keys nest tables without a bracketed header.
server.host = "0.0.0.0"
server.port = 8080
server.tls.cert = "cert.pem"
# equivalent to:
# [server]
# host = "0.0.0.0"
# port = 8080
#
# [server.tls]
# cert = "cert.pem"
Useful for tiny configs; the bracketed form reads better past five lines.
TOML vs YAML vs JSON#
TOML |
typed values, dates first-class, explicit sections, no indentation rules. Best for project / tool config. |
|---|---|
YAML |
terser, indentation-significant, anchors / aliases, reference cycles possible. Best for human-edited configs with reused fragments (CI pipelines, k8s). |
JSON |
no comments, no dates, no trailing commas, strict. Best for wire / machine-to-machine, not for hand edit. |
Operators meet TOML when the project already picked it
(pyproject.toml, Cargo.toml). YAML still dominates k8s
and CI; JSON dominates wire payloads.
Tooling#
Tool |
Notes |
|---|---|
Standalone CLI formatter and linter. Speaks the spec precisely; integrates with editors. |
|
tomli /
|
Read-only parser in the stdlib. |
Writer side; not in stdlib. |
|
Reference Rust parser. |
|
Convert between YAML, JSON, TOML, HCL. |
|
Convert TOML to JSON from the command line. |
$ taplo fmt pyproject.toml
$ taplo lint pyproject.toml
$ python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb')))"
$ yj -tj < config.toml > config.json
Pitfalls#
A table can only be defined once. Redefining
[database]is an error; sub-tables under a previous table are fine.Inline tables are immutable after their declaration — you cannot add keys to an inline table elsewhere in the file.
Dotted keys and bracketed headers interact subtly. Stick to one form per file.
TOML strings are UTF-8; ensure your editor doesn’t write a BOM (some parsers reject it).
References#
Awesome TOML, a curated list of parsers and tools.
YAML for the indentation-driven alternative.
JSON for the strict machine-to-machine alternative.
INI for the legacy ancestor.