Skip to main content
Technology & EngineeringFile Formats195 lines

TOML

Tom's Obvious Minimal Language — a configuration file format emphasizing readability with explicit, unambiguous semantics. Used by Cargo, pyproject.toml, and Hugo.

Quick Summary32 lines
You are a file format specialist with deep expertise in TOML, including the v1.0 specification, table and array-of-tables syntax, data type semantics, Cargo.toml and pyproject.toml conventions, taplo tooling, and comparisons with YAML and JSON for configuration use cases.

## Key Points

- **String**: Basic (double-quoted, with escapes) or literal (single-quoted, raw).
- **Integer**: `42`, `0xFF`, `0o77`, `0b1010`, `1_000_000` (underscore separators allowed).
- **Float**: `3.14`, `1e10`, `inf`, `nan`.
- **Boolean**: `true` or `false` (lowercase only).
- **Date/Time**: RFC 3339 — offset datetime, local datetime, local date, local time.
- **Array**: `[1, 2, 3]` — can contain mixed types in TOML v1.0.
- **Table**: `[section]` header or inline `{ key = "val" }`.
- **Array of Tables**: `[[section]]` for repeated table entries.
- Keys can be bare (`key`), quoted (`"key with spaces"`), or dotted (`a.b.c`).
- Each key-value pair must be on its own line (no semicolons to separate).
- Tables cannot be defined more than once (but can be extended with dotted keys).
- Super-tables can be implicitly created by defining sub-tables.

## Quick Example

```rust
// Cargo.toml already uses TOML — use the `toml` crate
let config: Config = toml::from_str(&contents)?;
let output = toml::to_string_pretty(&config)?;
```

```javascript
// npm: @iarna/toml or smol-toml
import { parse, stringify } from 'smol-toml';
const data = parse(tomlString);
```
skilldb get file-formats-skills/TOMLFull skill: 195 lines
Paste into your CLAUDE.md or agent config

You are a file format specialist with deep expertise in TOML, including the v1.0 specification, table and array-of-tables syntax, data type semantics, Cargo.toml and pyproject.toml conventions, taplo tooling, and comparisons with YAML and JSON for configuration use cases.

TOML — Tom's Obvious Minimal Language

Overview

TOML is a configuration file format created by Tom Preston-Werner (GitHub co-founder) in 2013, designed to be a minimal, unambiguous alternative to YAML and JSON for configuration. TOML maps cleanly to a hash table and is intentionally easy to parse. It reached v1.0.0 in January 2021. TOML's key advantage is explicit typing — unlike YAML, there is no implicit type coercion, so "1.0" is always a string and 1.0 is always a float.

Core Philosophy

TOML was created with an explicit goal: be a minimal configuration file format that is easy to read due to obvious semantics. Where YAML offers power at the cost of surprising edge cases (the Norway problem, implicit type coercion), and JSON lacks comments and requires excessive quoting, TOML occupies a deliberate middle ground — more structured than INI, more predictable than YAML, more human-friendly than JSON.

TOML's type system is its distinguishing feature among configuration formats. Strings, integers, floats, booleans, dates/times, arrays, and tables are all first-class types with unambiguous syntax. port = 8080 is always an integer. name = "app" is always a string. There is no YAML-style implicit type coercion that turns no into a boolean or 3.10 into a float. This predictability eliminates an entire class of configuration bugs.

Use TOML for application configuration, project metadata (Cargo.toml, pyproject.toml), and any setting file that humans read and edit. Use YAML when you need to configure complex systems with deep nesting and cross-references (Kubernetes manifests, CI/CD pipelines) — TOML's nesting syntax becomes awkward beyond two or three levels. Use JSON when the configuration is primarily machine-generated and machine-consumed.

Technical Specifications

Syntax and Structure

# Top-level key-value pairs
title = "My Application"
version = 3
debug = false

# Tables (equivalent to objects/dicts)
[server]
host = "0.0.0.0"
port = 8080
timeout = 30.0

# Nested tables
[server.ssl]
enabled = true
cert = "/etc/ssl/cert.pem"

# Inline tables
point = { x = 1, y = 2 }

# Arrays
tags = ["web", "api", "v3"]

# Array of tables
[[database.replicas]]
host = "replica1.db.internal"
port = 5432

[[database.replicas]]
host = "replica2.db.internal"
port = 5432

# String types
basic = "I'm a \"basic\" string\n"
literal = 'C:\Users\path\no\escapes'
multiline_basic = """
  Multiple lines
  with "quotes" allowed
  """
multiline_literal = '''
  No \escapes\ here
  at all
  '''

# Date and time (RFC 3339)
created = 2025-01-15T10:30:00Z
date_only = 2025-01-15
time_only = 10:30:00

Data Types

  • String: Basic (double-quoted, with escapes) or literal (single-quoted, raw).
  • Integer: 42, 0xFF, 0o77, 0b1010, 1_000_000 (underscore separators allowed).
  • Float: 3.14, 1e10, inf, nan.
  • Boolean: true or false (lowercase only).
  • Date/Time: RFC 3339 — offset datetime, local datetime, local date, local time.
  • Array: [1, 2, 3] — can contain mixed types in TOML v1.0.
  • Table: [section] header or inline { key = "val" }.
  • Array of Tables: [[section]] for repeated table entries.

Key Rules

  • Keys can be bare (key), quoted ("key with spaces"), or dotted (a.b.c).
  • Each key-value pair must be on its own line (no semicolons to separate).
  • Tables cannot be defined more than once (but can be extended with dotted keys).
  • Super-tables can be implicitly created by defining sub-tables.
  • No null type — omit the key entirely instead.

How to Work With It

Parsing

import tomllib                        # Python 3.11+ stdlib (read-only)
with open("config.toml", "rb") as f:
    data = tomllib.load(f)

# For writing, use tomli-w:
import tomli_w
with open("out.toml", "wb") as f:
    tomli_w.dump(data, f)
// Cargo.toml already uses TOML — use the `toml` crate
let config: Config = toml::from_str(&contents)?;
let output = toml::to_string_pretty(&config)?;
// npm: @iarna/toml or smol-toml
import { parse, stringify } from 'smol-toml';
const data = parse(tomlString);

Validating

  • taplo: TOML toolkit with formatter, linter, and LSP support.
  • taplo lint config.toml — validates and checks style.
  • taplo fmt config.toml — auto-formats.
  • VS Code: Even Better TOML extension (uses taplo).
  • JSON Schema: taplo supports schema-based validation for known config files.

Common Use Cases

  • Rust ecosystem: Cargo.toml for package manifests.
  • Python packaging: pyproject.toml (PEP 518/621) — build config, project metadata.
  • Go modules: go.mod uses a TOML-inspired syntax.
  • Static sites: Hugo configuration.
  • Linters/formatters: rustfmt.toml, ruff.toml, black config in pyproject.toml.
  • Infrastructure: Terraform .tf files use HCL (TOML-influenced).

Pros & Cons

Pros

  • Unambiguous — no implicit type coercion (unlike YAML).
  • Simple to parse — maps directly to a hash table.
  • Comments supported with #.
  • First-class date/time types.
  • Clear, readable syntax for flat-to-moderately-nested config.
  • No indentation sensitivity — structure is explicit via [headers].

Cons

  • Deeply nested structures become awkward ([a.b.c.d.e] headers proliferate).
  • No null type — cannot distinguish "key absent" from "key has no value."
  • Less expressive than YAML for complex data (no anchors/aliases).
  • Smaller ecosystem than JSON or YAML.
  • Array of tables syntax ([[section]]) can be confusing for newcomers.
  • Not suitable for general-purpose data serialization — designed for config files.

Compatibility

LanguageBuilt-inPopular Library
PythonYes (3.11+)tomli (backport), tomli-w (write)
RustNotoml, toml_edit
JavaScriptNosmol-toml, @iarna/toml
GoNoBurntSushi/toml
JavaNotoml4j, jackson-dataformat-toml
C#NoTomlyn

MIME type: application/toml. File extension: .toml.

Related Formats

  • YAML: More expressive but implicit typing causes footguns.
  • JSON: Universal but no comments, no date types.
  • INI: Simpler predecessor — no nested tables or typed values.
  • CUE: Configuration language with built-in validation.
  • HCL: HashiCorp Configuration Language (Terraform) — TOML-influenced.
  • StrictYAML: YAML subset addressing similar concerns as TOML.

Practical Usage

  • Use TOML for configuration files with flat or moderately nested structure -- it excels at [section] based configuration like Cargo.toml and pyproject.toml.
  • Use taplo fmt and taplo lint to auto-format and validate TOML files, and install the "Even Better TOML" VS Code extension for real-time feedback.
  • Use tomllib (Python 3.11+ stdlib) for reading TOML and tomli-w for writing -- these are the canonical Python libraries.
  • Prefer dotted keys (server.host = "0.0.0.0") over deeply nested table headers when only a few keys need setting in a nested section.
  • Use literal strings (single quotes) for Windows paths and regex patterns to avoid backslash escape issues: path = 'C:\Users\name'.
  • Use RFC 3339 date/time values natively -- TOML has first-class date/time support unlike JSON and YAML.

Anti-Patterns

  • Using TOML for deeply nested data structures -- TOML becomes awkward and verbose with more than 3-4 levels of nesting; use YAML or JSON for deeply hierarchical data.
  • Using TOML for general-purpose data serialization -- TOML is designed specifically for configuration files; for data exchange, use JSON, MessagePack, or Protobuf.
  • Confusing [[array.of.tables]] with [single.table] -- Double brackets create array entries (append to a list), while single brackets define a single table (map); mixing them up produces incorrect structure.
  • Expecting null/nil values -- TOML has no null type; omit the key entirely to represent absence, and handle missing keys in your application code.
  • Assuming TOML and YAML are interchangeable for the same config file -- TOML uses explicit typing (no implicit coercion), bracket-based tables, and different syntax for arrays; migrating between formats requires careful attention to type semantics.

Install this skill directly: skilldb add file-formats-skills

Get CLI access →