Skip to content
Free Tool Arena

Developers & Technical · Guide · Developer Utilities

How to work with TOML

TOML syntax (scalars, tables, arrays), version differences (0.5 vs 1.0), TOML vs JSON vs YAML, round-trip parsers, gotchas, tooling.

Updated April 2026 · 6 min read

TOML (Tom’s Obvious Minimal Language) is a config-file format designed to be easier to read than JSON and less whitespace-sensitive than YAML. It powers Cargo.toml, pyproject.toml, hugo.toml, and many other project configs. This guide covers TOML syntax (scalars, tables, arrays, inline), how it compares to JSON and YAML, version differences (0.5 vs 1.0), common gotchas (datetimes, nested tables, mixing dotted and header tables), and when to pick TOML vs the alternatives.

Advertisement

The basics

title = "Example"
port = 8080
enabled = true

[server]
host = "localhost"
timeout = 30

[[plugins]]
name = "auth"
version = "1.2.0"

[[plugins]]
name = "logging"
version = "0.9.0"

Top-level is a table. Sections in square brackets are sub-tables. Double brackets [[...]] are arrays of tables.

Scalar types

String: double-quoted (with escapes) or literal single-quoted (raw, no escapes): "hello", 'raw\string'.

Multi-line string: triple quotes — """...""" or '''...'''.

Integer: 42, -17, 0xdeadbeef (hex), 0o777 (octal), 0b1010 (binary).

Float: 3.14, 1e10, inf, nan.

Boolean: true, false. Lowercase only.

Datetime (RFC 3339): 2026-04-22T10:30:00Z, 2026-04-22 (date), 10:30:00 (local time).

Array: [1, 2, 3], ["a", "b"]. Homogeneous in TOML 0.5 and earlier; mixed-type arrays legal in 1.0+.

Tables

A table is a set of key/value pairs. Three ways to declare:

Header table:

[server]
host = "localhost"
port = 8080

Inline table:

server = { host = "localhost", port = 8080 }

Dotted keys:

server.host = "localhost"
server.port = 8080

All three produce the same logical structure. Pick one style per file for readability.

Nested tables

[database]
url = "postgres://..."

[database.pool]
min = 2
max = 10

The database.pool header names the nested table. Dotted key style also works:

[database]
url = "postgres://..."
pool.min = 2
pool.max = 10

Arrays of tables

Double-bracket headers define array elements, each its own table:

[[products]]
name = "Widget"
price = 9.99

[[products]]
name = "Gadget"
price = 14.99

Equivalent JSON: "products":[{"name":"Widget",...},{"name":"Gadget",...}].

TOML vs JSON vs YAML

JSON: machine-to-machine. Verbose, no comments, bad for config.

YAML: human-friendly but whitespace-sensitive. Subtle bugs (no parsing as false; unquoted 1.0 becoming a float). Anchors and references add power but confusion.

TOML: config-focused. No whitespace rules. Comments supported. Types are explicit. Less expressive than YAML (no merging, no references).

Rule of thumb: TOML for project config, JSON for API payloads and machine-generated data, YAML when you need anchors/overrides or match an existing ecosystem (Kubernetes, Ansible).

TOML version differences

0.5 → 1.0: 1.0 allows mixed-type arrays, clarified datetime handling, tightened redeclaration rules.

Parser compatibility: old parsers may reject 1.0 files that use mixed arrays. When sharing TOML, target 1.0 and document it.

Check parser version: toml_edit (Rust), tomli (Python 3.11+ stdlib), @iarna/toml (JS). Check your parser supports 1.0 if you use mixed arrays.

Comments

# full-line comment
port = 8080  # inline comment

Start with #. No multi-line comment syntax. Comments are not preserved by most parsers unless you use a round-trip parser (e.g., toml_edit).

Round-trip preservation

Most TOML parsers throw away comments and reorder keys. For tools that need to edit config files while preserving formatting (think Cargo editing Cargo.toml), use a round-trip parser: toml_edit in Rust, tomlkit in Python.

Common gotchas

Redefining tables: you can’t declare [server] twice. Second header = error.

Mixing header and dotted declarations of the same path:

[server]
host = "x"
server.port = 8080  # error — server already declared

Datetime timezone: offset datetimes vs local datetimes matter. 2026-04-22T10:30:00Z is UTC; 2026-04-22T10:30:00 has no offset (local time).

Hex/octal/binary only for integers: not for floats.

Raw strings can’t contain single quotes: use basic strings with escapes or multiline literal.

TOML to JSON and back

TOML converts cleanly to JSON (TOML is strictly less expressive — comments and some number formats lost). JSON to TOML is lossy in one case: JSON doesn’t distinguish integer and float, so 1 might round-trip as 1 or 1.0 depending on the converter.

Most tools (including our converter) parse TOML into an internal object, then serialize to JSON. Clean for most data; datetimes may need special handling.

When to pick TOML

Project config: Cargo.toml, pyproject.toml made it a de facto standard.

Tool config: netlify.toml, hugo.toml, black.toml.

Config that humans edit: clearer than JSON, less bite than YAML.

Avoid for: anything that needs anchors/references, deep nesting (YAML is often better), or binary data (base64 into strings gets ugly).

Common mistakes

Using YAML-style list indentation. TOML arrays use brackets, not hyphens.

Forgetting quotes on string values. Unquoted strings are illegal except for bare keys.

Mixing dotted and header declarations for one path. Parser error.

Treating TOML dates as strings. They’re first-class datetime types. Use the parsed datetime object.

Expecting round-trip formatting. Most parsers reformat. Use a round-trip parser if formatting matters.

Run the numbers

Convert TOML to JSON instantly with the TOML to JSON converter. Pair with the YAML/JSON converter when comparing config formats, and the JSON formatter to tidy the output.

Advertisement

Found this useful?Email