TOML Cheatsheet - Tables, Arrays & Cargo.toml
Tools like Cargo, Hugo and Greenlet configure with TOML, whose explicit [table] blocks and key = value syntax make it more readable than JSON and support comments. This reference groups 6 sections: basic types, date-time, four string flavors, arrays and tables, arrays of tables, plus a ready-to-adapt Cargo.toml example. Mirror the structure while writing a dependency table or nested section, and look up string escaping or date-time offsets as needed to avoid common type and indentation ambiguity. After reading you can maintain Cargo.toml and similar TOML config on your own.
Basic Types 11
# this is a commentkey = "value"key = 'value'int = 42hex = 0xFFoct = 0o17bin = 0b101num = 1_000_000float = 3.14flt = infbool = trueDate & Time 5
date = 2026-07-19time = 14:30:00datetime = 2026-07-19T14:30:00datetime = 2026-07-19T14:30:00Zdatetime = 2026-07-19T14:30:00+08:00Strings 4
str = "Hello\nWorld"str = """Hello\nWorld"""str = 'C:\\path\\to\'str = '''C:\\path\\to\'''Arrays & Tables 6
array = [1, 2, 3]array = [
1,
2,
3,
][table][table.subtable]physical.color = "orange"inline = { key1 = "value1", key2 = 2 }Array of Tables 4
[[products]]name = "Apple"[[products]]name = "Banana"Cargo.toml Example 8
[package]name = "myapp"version = "0.1.0"edition = "2021"[dependencies]serde = "1.0"serde = { version = "1.0", features = ["derive"] }[dev-dependencies]Command Examples
A complete Cargo.toml skeleton
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = "1.0"
serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]The shorthand and the feature-bearing form cannot both be written for one package — the later declaration overrides the earlier. Only the second form enables the derive feature; the shorthand declares the version range alone.
Array tables: repeating a name appends an element
[[products]]
name = "Apple"
[[products]]
name = "Banana"The two name keys belong to two separate elements and are not a duplicate-key conflict. Written as [products] instead, the second declaration errors out as a redefinition. Element order follows declaration order.
The four string forms and how each handles escapes
str = "Hello\nWorld"
str = 'C:\\path\\to'
str = """Hello\nWorld"""
str = '''C:\\path\\to'''The double-quoted form interprets sequences such as \n; the single-quoted form keeps backslashes literal, which is exactly why Windows paths suit single quotes. Triple-quoted forms allow the value to span lines, and whether escapes are interpreted again depends on the quote character used.
Three ways to express nesting: tables, inline tables, dotted keys
[table]
[table.subtable]
physical.color = "orange"
inline = { key1 = "value1", key2 = 2 }All three produce identical nesting, so choose on readability: consecutive dotted keys for closely related settings, sub-tables when a block needs to expand over several lines, and inline tables for small single-line structures.
Common Pitfalls
- Booleans must be bare true/false. Quoting them yields a string, so the program receives text instead of a switch, and config validation tends to fail silently at exactly this point.
- Never declare the same package twice, once shorthand and once with features — the later line overrides the earlier one and the feature silently disappears.
- Array entries sharing one [table] name is a redefinition error. Use [[array]] whenever the number of entries follows the content.
- Timestamps that cross system boundaries need an explicit offset or UTC; a zone-less value resolves to different instants under different host timezones.
- TOML supports only # line comments, with no block comment form. C-style comments or a leading semicolon are both parsed as invalid syntax.
Tips
- TOML prioritizes readability and fits config files better than JSON.
- Strings come in basic (double-quoted, escapes) and literal (single-quoted, no escapes).
- Tables [table] and arrays of tables [[array]] are TOML's core structures.
FAQ
What is the difference between [table] and [[array]]?
[table] declares one named block of keys and may appear only once for a given name, while [[array]] declares one element of an array — repeating the header appends another entry, and the keys that follow belong to that element rather than to the container. Practically: use [[array]] when the structure repeats and the entry count follows the content (a set of dependencies, a group of CI jobs), and [table] when the shape is fixed and you are simply naming a group of parameters (package metadata, a dependency table). Declaring an array table as if it were a plain table produces a duplicate-key error as soon as it repeats.
When should I choose a basic string over a literal string?
It depends on whether the value needs escapes or special characters interpreted. key = "value" is a basic string and interprets sequences such as \n, \t, backslash and double quote — use it when the value spans lines or contains special characters. key = 'value' is a literal string and is taken exactly as written, with no escape processing at all. Windows paths are the canonical case: the backslashes in C:\Users must be doubled in a basic string or they open an escape sequence, while a literal string takes them verbatim. The multi-line forms follow the same split: triple-double-quote keeps escapes, triple-single-quote keeps the content raw.
What happens if a boolean is written as the string "true"?
It becomes a string, not a boolean. Quoted "true" is an ordinary string and is a distinct type from the bare keyword true — a difference that surfaces immediately during config validation or at read time, where the program receives text instead of a switch. TOML booleans are the lowercase true and false only, with no quotes. A related trap is underscore-separated numerals: num = 1_000_000 is a valid integer written for readability, but mixing such forms carelessly yields a float where an integer was intended.
Are dotted keys and sub-tables the same thing?
They are structurally equivalent but written differently. physical.color = "orange" is a dotted key: it can appear anywhere in the file, and the dots in the key are hierarchy separators. [physical.color] is a sub-table and occupies its own line. Both produce the same nested structure and do not conflict, but readability differs — a group of related settings reads more compactly as consecutive dotted keys, while a block that needs several lines is clearer as a sub-table. The inline table inline = { key1 = "value1", key2 = 2 } is a third form, suited to small structures that fit on one line.
How do I choose among the date and time forms?
Decide by whether timezone information is needed. date = 2026-07-19 is a local date, time = 14:30:00 a local time, and datetime = 2026-07-19T14:30:00 a local date-time without a zone; a trailing Z marks UTC and an offset such as +08:00 marks an explicit zone. Any timestamp crossing system boundaries should carry an offset or be expressed in UTC, because a zone-less value resolves to different instants depending on the host or container timezone — and that implicit conversion is very hard to trace back.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us