TOML Cheatsheet

Keys and Values

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

The shape of a TOML file

TOML 1.0.0. Every line is either a comment, a [table] header, or exactly one key = value pair. Every value needs a key, and every pair lives on one line. There is no bare value, no anonymous array at the top level, and no way to split a pair across lines except inside a multi-line string or array.

# a comment runs to end of line
title = "TOML Example"
enabled = true
port = 8080

[owner]
name = "Tom Preston-Werner"

Whitespace around = is free, both \n and \r\n are valid line endings, and the file must be valid UTF-8. A BOM is not part of the spec, and Python's tomllib rejects one with Invalid statement (at line 1, column 1).

Bare keys

A bare key is A-Za-z0-9_-. That includes all-digit keys, which stay strings.

key = "value"
bare_key = "underscores fine"
bare-key = "dashes fine"
1234 = "digits fine"

parses to:

{"key": "value", "bare_key": "underscores fine",
 "bare-key": "dashes fine", "1234": "digits fine"}

Note the key is the string "1234", not the integer 1234.

An empty bare key is not allowed. = 1 is a syntax error.

Quoted keys

Anything else needs quotes, and both string forms work as keys.

"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'literal key' = "value"
'quoted "value"' = "value"
"" = "an empty key is legal, but do not"

Basic ("...") quoted keys process escapes. Literal ('...') quoted keys do not, which is what you want for a key containing a backslash.

Dotted keys

A dot in a key creates nested tables. These two files are identical:

name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
name = "Orange"

[physical]
color = "orange"
shape = "round"

[site]
"google.com" = true

Both parse to:

{"name": "Orange",
 "physical": {"color": "orange", "shape": "round"},
 "site": {"google.com": true}}

Whitespace around the dots is ignored, so a . b . c = 1 is the same as a.b.c = 1. Write it without spaces anyway. Only the last segment is the key, every earlier segment names a table.

Keys are case sensitive and cannot be redefined

abc = 1
ABC = 2      # a different key, both survive
a = 1
a = 2        # ERROR: Cannot overwrite a value

Python's tomllib reports TOMLDecodeError: Cannot overwrite a value (at line 2, column 6). There is no last-wins behaviour anywhere in TOML, which is the single biggest ergonomic difference from YAML. Defining the same table twice is an error too, and so is turning a defined value into a table.

Extending a dotted-key namespace is fine, as long as you never overwrite a concrete value:

a.b = 1
a.c = 2      # fine, both under [a]

Value types at a glance

TypeExample
string"basic" · 'literal' · """multi""" · '''multi'''
integer42 · -17 · 1_000 · 0xFF · 0o755 · 0b1010
float3.14 · -0.01 · 5e+22 · inf · nan
booleantrue · false (lowercase only)
offset date-time1979-05-27T07:32:00Z
local date-time1979-05-27T07:32:00
local date1979-05-27
local time07:32:00
array[1, 2, 3]
inline table{x = 1, y = 2}
table[header]
array of tables[[header]]

True is a syntax error, not a string. So is a bare word: mode = production fails, it needs quotes. TOML has no null type. To express absence you omit the key entirely, and the reader supplies a default.

Comments

# starts a comment and runs to end of line. There is no block comment form.

# full-line comment
key = "value"  # trailing comment
str = "a # inside a string is literal"
arr = [
  1,  # comments work inside multi-line arrays
  2,
]

A # inside any string form is literal. Control characters other than tab are not allowed in a comment, which matters only if you paste something odd.