TOML Cheatsheet

Arrays and Inline Tables

Use this TOML reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Arrays

Square brackets, comma separated. Values may be any type, including a mix.

integers = [1, 2, 3]
colors = ["red", "yellow", "green"]
nested = [[1, 2], [3, 4, 5]]
nested_mixed = [[1, 2], ["a", "b", "c"]]
strings = ["all", 'strings', """are the same""", '''type''']
mixed = [1, "two", 3.0, true, [4]]
empty = []

parses to:

{"integers": [1, 2, 3], "colors": ["red", "yellow", "green"],
 "nested": [[1, 2], [3, 4, 5]],
 "nested_mixed": [[1, 2], ["a", "b", "c"]],
 "strings": ["all", "strings", "are the same", "type"],
 "mixed": [1, "two", 3.0, true, [4]], "empty": []}

Heterogeneous arrays are legal in TOML 1.0.0. They were forbidden in earlier drafts, so older parsers and some Go and Rust libraries still reject them. If a config has to be read by an unknown parser, keep arrays uniform. Whatever deserializes into a typed struct will reject a mixed array anyway.

Multi-line arrays and trailing commas

An array may span lines freely. Newlines and comments are allowed anywhere inside it, and a trailing comma after the last element is allowed.

dependencies = [
  "requests>=2.31",   # http
  "pydantic>=2.0",
  "click>=8.1",       # trailing comma below is fine
]

matrix = [
  [1, 0],
  [0, 1],
]

This is the main readability win over JSON: a one-line diff when you add a dependency, plus a comment per line saying why it is there.

Inline tables

{ } with key = value pairs. An inline table is a table, identical in the data model to a [header] block, just written compactly.

name = {first = "Tom", last = "Preston-Werner"}
point = {x = 1, y = 2}
animal = {type = {name = "pug"}}
empty = {}

is exactly:

[name]
first = "Tom"
last = "Preston-Werner"

[point]
x = 1
y = 2

[animal.type]
name = "pug"

[empty]

Inline table restrictions

Three hard rules, and all three catch people used to JSON5 or JavaScript.

RuleBadError
single line only{ newline x = 1 }Invalid initial character for a key part
no trailing comma{x = 1,}Invalid initial character for a key part
immutable once closedp = {x=1} then [p.q]Cannot declare ('p', 'q') twice
immutable once closedp = {x=1} then p.y = 2Cannot mutate immutable namespace ('p',)

That immutability is the important one. Once an inline table is written, nothing may add to it, not a dotted key, not a header, not a nested header. So an inline table is for a small, complete, final value. Anything you expect to grow gets a [header].

Arrays of inline tables

The compact alternative to [[header]], good for short uniform rows.

points = [
  {x = 1, y = 2, z = 3},
  {x = 7, y = 8, z = 9},
]

[[redirects]]
from = "/old"
to = "/new"
status = 301

points and a [[points]] block produce identical data. Note the trailing comma after the last inline table is fine, because that comma belongs to the enclosing array, not to the inline table. The forbidden case is a comma inside the braces.

Choosing between the four container forms

You haveUse
a list of scalarstags = ["a", "b"]
a long list of scalarsmulti-line array, one per line
a small fixed recordinline table {x = 1, y = 2}
a record with many fields or comments[header]
a few short uniform recordsarray of inline tables
several records with sub-tables[[header]]
something a tool will append to[[header]], never an array literal

That last row is the practical rule. A generator can append a new [[x]] block to the end of a file, but it cannot append to an array literal without rewriting the value, and it cannot append to an inline table at all.

Whitespace and formatting notes

- Whitespace around =, inside brackets, and around commas is free. - Inside an inline table, one space after { and before } is the conventional spelling ({ x = 1 }), but the tight form is equally valid. - Comments are allowed inside multi-line arrays and not inside inline tables. A comment runs to end of line, and an inline table cannot contain a newline, so { x = 1 # c fails with Unclosed inline table. - taplo fmt is the usual TOML formatter and taplo lint validates a file against a schema. cargo fmt formats Rust and never touches Cargo.toml.