What is TOML?
TOML is a configuration file format that aims to be easy to read due to obvious semantics. Created by Tom Preston-Werner (co-founder of GitHub), it's designed to map unambiguously to a hash table.
# This is a TOML document
title = "My Application"
version = "1.0.0"
[database]
host = "localhost"
port = 5432
enabled = true
[servers.alpha]
ip = "10.0.0.1"
role = "primary"
[servers.beta]
ip = "10.0.0.2"
role = "replica"
TOML takes the best parts of INI files and adds proper data types, nested tables, and arrays. Unlike YAML, it's impossible to shoot yourself in the foot with whitespace.
Basic Syntax
| Type | TOML | Notes |
|---|---|---|
| String | name = "hello" | Double quotes required |
| Integer | port = 8080 | Underscores allowed: 1_000_000 |
| Float | pi = 3.14159 | Standard notation |
| Boolean | enabled = true | Lowercase only |
| Date | date = 2024-01-30 | ISO 8601 format |
| DateTime | ts = 2024-01-30T12:00:00Z | With time and timezone |
| Array | ports = [80, 443, 8080] | Square brackets |
| Table | [section] | Creates a new section |
Strings
TOML has four string types:
# Basic string - escapes work
basic = "Hello\nWorld"
# Literal string - no escapes
literal = 'C:\Users\name'
# Multi-line basic
multiline = """
This spans
multiple lines.
"""
# Multi-line literal
multiline_literal = '''
Regex: \d+\.\d+
No escaping needed.
'''
Tables (Sections)
Tables are collections of key-value pairs:
# Standard table
[server]
host = "localhost"
port = 8080
# Nested tables
[database.primary]
host = "db1.example.com"
[database.replica]
host = "db2.example.com"
# Inline table (for simple cases)
point = { x = 10, y = 20 }
Arrays
# Simple array
colors = ["red", "green", "blue"]
# Multi-line array
dependencies = [
"numpy",
"pandas",
"matplotlib",
]
# Array of tables (for repeated structures)
[[products]]
name = "Widget"
price = 9.99
[[products]]
name = "Gadget"
price = 19.99
The [[products]] syntax creates an array of tables—each section adds a new item to the products array.
Where You'll See This
- Rust -
Cargo.tomlfor package management - Python -
pyproject.toml(PEP 518) - Go -
go.modinfluenced by TOML - Hugo - Static site configuration
- InfluxDB - Database configuration
- Netlify -
netlify.tomlfor deployments
Common Gotchas
[servers] creates a single table. [[servers]] creates an array of tables. Mixing them up causes confusing errors.
Keys can be bare (key = "value"), quoted ("key-with-dashes" = "value"), or dotted (a.b.c = "value"). Dotted keys create nested tables inline.
- No null type - TOML has no
null. Omit the key or use an empty string. - Tables must be defined before use - You can't add keys to a table after defining a subtable.
- Case-sensitive -
Keyandkeyare different keys. - Dates are strict - Must be valid ISO 8601 dates. No
2024-1-5, must be2024-01-05. - No trailing commas in inline tables -
{a = 1,}is invalid.
TOML vs Alternatives
| TOML | YAML | JSON | INI | |
|---|---|---|---|---|
| Readability | Excellent | Good | Verbose | Good |
| Types | Rich | Rich | Basic | None |
| Comments | # | # | None | ; or # |
| Nesting | Limited | Unlimited | Unlimited | Flat |
| Gotchas | Few | Many | Some | Many |
| Best for | Config files | Complex config | Data exchange | Simple config |
Real-World Example: Cargo.toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"
authors = ["Developer <dev@example.com>"]
description = "A sample Rust application"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
[dev-dependencies]
criterion = "0.5"
[[bin]]
name = "my-app"
path = "src/main.rs"
[profile.release]
opt-level = 3
lto = true
In Code
// Node.js with @iarna/toml
const TOML = require('@iarna/toml');
// Parse TOML string
const config = TOML.parse(`
[server]
host = "localhost"
port = 8080
`);
// Convert to TOML string
const tomlString = TOML.stringify({
server: { host: 'localhost', port: 8080 }
});
# Python with tomllib (built-in 3.11+)
import tomllib
with open('config.toml', 'rb') as f:
config = tomllib.load(f)
# For writing, use tomli-w
import tomli_w
with open('config.toml', 'wb') as f:
tomli_w.dump(config, f)
Try It
Convert TOML to JSON"TOML: Because Tom wanted a config format that wouldn't make him question his life choices at 3 AM."