DevToolBoxGRATIS
Blogg

TOML Syntaks og Konfigurasjonsguide

9 min lesningby DevToolBox

TOML (Tom's Obvious Minimal Language) is a configuration file format designed to be easy to read thanks to its obvious semantics. Created by Tom Preston-Werner (GitHub co-founder) in 2013, TOML maps unambiguously to a hash table and is now the standard config format for Rust, Python, and many other tools. This comprehensive TOML syntax guide covers every feature with practical examples.

Convert between TOML and YAML instantly with our free tool →

Convert between JSON and YAML with our free tool →

1. What Is TOML?

TOML stands for Tom's Obvious Minimal Language. It was created to be a minimal configuration file format that is easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table and should be easy to parse into data structures in a wide variety of languages.

TOML's design goals are:

  • Minimal — the spec is intentionally small and stable
  • Obvious — semantics are clear; no implicit type coercion like YAML
  • Unambiguous — every valid TOML document has exactly one meaning
  • Hash-table friendly — maps directly to dictionaries/objects/maps

Compared to JSON, TOML supports comments, native date/time types, and multiline strings. Compared to YAML, TOML avoids the pitfalls of implicit type coercion (the infamous "Norway problem" where NO becomes false) and indentation-sensitivity. TOML reached v1.0.0 in January 2021, making it a stable specification.

# example.toml — a simple TOML configuration
title = "My Application"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
enabled = true
ports = [8001, 8001, 8002]
data = [["delta", "phi"], [3.14]]
temp_targets = { cpu = 79.5, case = 72.0 }

2. Basic Data Types

TOML supports seven data types natively. Each value must be one of these types:

Strings

TOML has four kinds of strings: basic, multi-line basic, literal, and multi-line literal.

# Basic string — supports escape sequences
name = "Tom Preston-Werner"
escaped = "Line 1\nLine 2\tTabbed"
unicode = "\u03B1 is alpha"

# Literal string — no escaping
winpath = 'C:\Users\Tom\config'
regex = '<\i\c*\s*>'

# Multi-line basic string
bio = """
Roses are red,
Violets are blue.\
  This line is joined."""

# Multi-line literal string
regex2 = '''
I [dw]on't need \d{2} escapes
'''

Integers

Integers are whole numbers. Underscores can be used for readability. Hexadecimal, octal, and binary representations are also supported.

# Integers
int1 = +99
int2 = 42
int3 = 0
int4 = -17

# Underscores for readability
big_number = 1_000_000
hex_color = 0xDEADBEEF

# Different bases
hex = 0xDEADBEEF    # hexadecimal
oct = 0o755          # octal (Unix permissions)
bin = 0b11010110     # binary

Floats

Floating-point numbers follow IEEE 754. Special values inf, +inf, -inf, and nan are supported.

# Floats
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
flt4 = 5e+22
flt5 = 1e06
flt6 = -2E-2

# Underscores
flt7 = 224_617.445_991_228

# Special float values
sf1 = inf      # positive infinity
sf2 = +inf     # positive infinity
sf3 = -inf     # negative infinity
sf4 = nan      # not a number

Booleans

Booleans are just what you expect — lowercase true and false. Unlike YAML, TOML does NOT accept yes, no, on, off as booleans.

# Booleans — only true and false (lowercase)
bool1 = true
bool2 = false

# INVALID in TOML (unlike YAML):
# bool3 = yes     # ERROR
# bool4 = no      # ERROR
# bool5 = on      # ERROR
# bool6 = off     # ERROR
# bool7 = True    # ERROR — must be lowercase

Date & Time

TOML has first-class date/time support with four types: offset datetime, local datetime, local date, and local time. All follow RFC 3339.

# Offset Date-Time (with timezone)
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00

# Local Date-Time (no timezone)
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999

# Local Date
ld1 = 1979-05-27

# Local Time
lt1 = 07:32:00
lt2 = 00:32:00.999999

3. Tables

Tables (also known as hash tables or dictionaries) are collections of key/value pairs. They appear in square brackets on a line by themselves. All key/value pairs after a table header belong to that table until the next table header.

# Standard table
[server]
host = "localhost"
port = 8080

[server.tls]
enabled = true
cert = "/path/to/cert.pem"
key = "/path/to/key.pem"

# Empty table
[empty_table]

Inline tables provide a compact syntax for simple tables. They must appear on a single line:

# Inline tables — must fit on one line
point = { x = 1, y = 2 }
animal = { type.name = "pug" }
name = { first = "Tom", last = "Preston-Werner" }

# Equivalent standard table form:
# [name]
# first = "Tom"
# last = "Preston-Werner"

Dotted keys allow defining nested tables without explicit headers:

# Dotted keys create nested tables implicitly
fruit.apple.color = "red"
fruit.apple.taste.sweet = true

# Equivalent to:
# [fruit.apple]
# color = "red"
#
# [fruit.apple.taste]
# sweet = true

4. Arrays

Arrays are ordered lists of values enclosed in square brackets. Arrays can contain values of the same type or mixed types (as of TOML v1.0).

# Basic arrays
integers = [1, 2, 3]
colors = ["red", "yellow", "green"]
nested_arrays = [[1, 2], [3, 4, 5]]

# Multi-line arrays (trailing comma OK)
hosts = [
  "alpha",
  "omega",
  "beta",    # trailing comma is allowed!
]

# Mixed-type arrays (TOML v1.0+)
mixed = [1, "two", 3.0, true, 1979-05-27]

Array of tables are defined using double brackets [[array]]. Each use of the double bracket adds an element to the array:

# Array of tables — each [[products]] adds an entry
[[products]]
name = "Hammer"
sku = 738594937

[[products]]    # empty table in the array

[[products]]
name = "Nail"
sku = 284758393
color = "gray"

# This is equivalent to the JSON:
# {
#   "products": [
#     { "name": "Hammer", "sku": 738594937 },
#     {},
#     { "name": "Nail", "sku": 284758393, "color": "gray" }
#   ]
# }

# Nested array of tables
[[fruits]]
name = "apple"

  [[fruits.varieties]]
  name = "red delicious"

  [[fruits.varieties]]
  name = "granny smith"

[[fruits]]
name = "banana"

  [[fruits.varieties]]
  name = "plantain"

5. String Types in Detail

TOML provides four types of strings to handle every use case:

Basic strings are surrounded by double quotes ("). Escape sequences like \n, \t, \\, \u0041 are supported.

# Basic string escape sequences
str1 = "I'm a string.\n"         # newline
str2 = "Tabs\there."              # tab
str3 = "Backslash: \\"           # literal backslash
str4 = "Quote: \""               # literal double quote
str5 = "Unicode: \u0041"         # 'A'
str6 = "Unicode: \U0001F600"     # emoji

Literal strings are surrounded by single quotes ('). No escaping is performed — what you see is what you get. Perfect for Windows paths and regex.

# Literal strings — no escape processing
winpath = 'C:\Users\nodejs\templates'
regex = '\d{2} files? found\?'

Multi-line basic strings are surrounded by three double quotes ("""). Newlines are preserved. A backslash at the end of a line trims the newline and subsequent whitespace.

# Multi-line basic string
str1 = """
Roses are red
Violets are blue"""

# Line-ending backslash trims newline + whitespace
str2 = """\
  The quick brown \
  fox jumps over \
  the lazy dog."""
# Result: "The quick brown fox jumps over the lazy dog."

Multi-line literal strings are surrounded by three single quotes ('''). No escaping, newlines preserved.

# Multi-line literal string — no escaping at all
regex_example = '''
I [dw]on't need \d{2} escapes
'''

raw_html = '''
<div>
  <p>Hello, world!</p>
</div>
'''

6. Date & Time Types

TOML has native support for four date/time formats, all based on RFC 3339:

Offset Date-Time — a full timestamp with timezone offset:

# Offset date-time — includes timezone
odt1 = 1979-05-27T07:32:00Z           # UTC
odt2 = 1979-05-27T00:32:00-07:00      # UTC-7
odt3 = 1979-05-27 07:32:00Z           # space instead of T is OK

Local Date-Time — no timezone information:

# Local date-time — no timezone
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999

Local Date — just the date:

# Local date
ld1 = 1979-05-27
ld2 = 2024-01-15

Local Time — just the time:

# Local time
lt1 = 07:32:00
lt2 = 00:32:00.999999
lt3 = 23:59:59

7. Comments

TOML supports single-line comments using the hash symbol (#). Comments run from the # character to the end of the line. TOML does not support multi-line comments — each line must start with its own #.

Comments can appear at the end of a line after a value, or on their own line. They cannot appear inside strings.

# This is a full-line comment
key = "value"  # This is an end-of-line comment

# Comments can explain configuration choices
[database]
# Use port 5432 for production PostgreSQL
port = 5432

# TOML does NOT support multi-line comments
# Each line needs its own # symbol
# Like these three lines

# You CANNOT put comments inside strings:
str = "has a # character"  # this is a comment, but the # in the string is literal

8. Cargo.toml — Rust Package Management

Cargo.toml is the manifest file for Rust projects. It defines the package metadata, dependencies, features, and build configuration. Understanding TOML syntax is essential for every Rust developer.

Key sections in Cargo.toml:

  • [package] — name, version, edition, description, license
  • [dependencies] — external crate dependencies
  • [dev-dependencies] — dependencies for tests and examples only
  • [build-dependencies] — dependencies for build scripts
  • [features] — conditional compilation flags
  • [workspace] — multi-package project configuration
  • [[bin]] — binary targets (array of tables)
# Cargo.toml — Complete Rust project example
[package]
name = "my-web-server"
version = "0.1.0"
edition = "2021"
authors = ["Alice <alice@example.com>"]
description = "A fast web server"
license = "MIT"
repository = "https://github.com/alice/my-web-server"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
axum = "0.7"
tracing = "0.1"

[dev-dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio-test = "0.4"

[features]
default = ["json"]
json = ["serde/derive"]
full = ["json", "tracing"]

# Workspace configuration for monorepos
[workspace]
members = [
  "crates/core",
  "crates/api",
  "crates/cli",
]

# Binary targets
[[bin]]
name = "server"
path = "src/main.rs"

[[bin]]
name = "cli"
path = "src/cli.rs"

# Build profile optimization
[profile.release]
opt-level = 3
lto = true
codegen-units = 1

9. pyproject.toml — Python Project Configuration

pyproject.toml is the standard configuration file for Python projects, defined in PEP 518 and PEP 621. It unifies build system configuration and tool settings into a single file, replacing setup.py, setup.cfg, and individual tool config files.

Common sections:

  • [build-system] — build backend specification (setuptools, hatch, poetry, etc.)
  • [project] — project metadata (name, version, dependencies, Python version)
  • [tool.ruff] — Ruff linter configuration
  • [tool.black] — Black formatter configuration
  • [tool.pytest.ini_options] — pytest settings
  • [tool.mypy] — mypy type checker settings
  • [tool.poetry] — Poetry-specific package management
# pyproject.toml — Complete Python project example
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my-package"
version = "1.0.0"
description = "A useful Python package"
readme = "README.md"
license = "MIT"
requires-python = ">=3.9"
authors = [
  { name = "Alice", email = "alice@example.com" },
]
dependencies = [
  "requests>=2.28",
  "pydantic>=2.0",
  "click>=8.0",
]

[project.optional-dependencies]
dev = [
  "pytest>=7.0",
  "ruff>=0.1",
  "mypy>=1.0",
]

[project.scripts]
my-cli = "my_package.cli:main"

# Ruff linter configuration
[tool.ruff]
line-length = 88
target-version = "py39"

[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]
ignore = ["E501"]

[tool.ruff.lint.isort]
known-first-party = ["my_package"]

# Black formatter
[tool.black]
line-length = 88
target-version = ["py39", "py310", "py311"]

# Pytest configuration
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra -q --strict-markers"
markers = [
  "slow: marks tests as slow",
  "integration: integration tests",
]

# Mypy type checking
[tool.mypy]
python_version = "3.9"
strict = true
warn_return_any = true

10. Other Notable TOML Configurations

TOML is used by many tools and platforms beyond Rust and Python:

Hugo — the popular static site generator uses hugo.toml (formerly config.toml) as its primary configuration format. Hugo supports TOML, YAML, and JSON, but TOML is the default and most common choice.

# hugo.toml — Hugo static site generator
baseURL = "https://example.com/"
languageCode = "en-us"
title = "My Hugo Site"
theme = "ananke"

[params]
author = "Alice"
description = "A blog about technology"
showReadingTime = true

[menu]
[[menu.main]]
name = "Home"
url = "/"
weight = 1

[[menu.main]]
name = "Posts"
url = "/posts/"
weight = 2

[[menu.main]]
name = "About"
url = "/about/"
weight = 3

Deno — the modern JavaScript/TypeScript runtime supports deno.toml alongside deno.json for project configuration. The TOML variant offers comments support, which JSON lacks.

# deno.toml — Deno runtime configuration
# Comments are supported (unlike deno.json)

[tasks]
dev = "deno run --watch main.ts"
test = "deno test --allow-read"
lint = "deno lint"

[fmt]
indentWidth = 2
lineWidth = 100
singleQuote = true

[lint.rules]
tags = ["recommended"]

[compilerOptions]
lib = ["deno.window"]

Taplo — a TOML toolkit that includes a formatter, validator, and language server. It provides IDE support for TOML files in VS Code and other editors via taplo.toml configuration.

git-cliff — a changelog generator configured via cliff.toml.

Starship — the cross-shell prompt uses starship.toml for customization.

Alacritty — the GPU-accelerated terminal emulator uses alacritty.toml for its configuration (migrated from YAML in 2023).

# starship.toml — cross-shell prompt
[character]
success_symbol = "[❯](bold green)"
error_symbol = "[❯](bold red)"

[git_branch]
symbol = "🌿 "
style = "bold purple"

[nodejs]
symbol = "⬢ "
detect_files = ["package.json", ".node-version"]

# alacritty.toml — terminal emulator
[font]
size = 14.0

[font.normal]
family = "JetBrains Mono"
style = "Regular"

[colors.primary]
background = "#1d1f21"
foreground = "#c5c8c6"

11. TOML vs YAML vs JSON

Here is a side-by-side comparison to help you decide which format to use:

FeatureTOMLYAMLJSON
CommentsYes (#)Yes (#)No
Native Date/TimeYes (RFC 3339)Yes (implicit)No (string only)
Deep NestingVerbose (table headers)Elegant (indentation)Good (braces)
AmbiguityNoneHigh (implicit coercion)None
Multiline StringsYes (""" and ''')Yes (| and >)No (\n only)
Primary EcosystemRust, Python, GoDevOps, K8s, AnsibleWeb APIs, Node.js
Spec SizeSmall (~3k words)Large (~80 pages)Tiny (~600 words)

12. Frequently Asked Questions

What is the difference between TOML and INI files?

While TOML looks similar to INI files with its [section] headers, TOML is a well-defined specification with strict typing, nested tables, arrays, date/time support, and Unicode handling. INI files have no formal specification, leading to inconsistent parsing across implementations. TOML can be thought of as a modern, standardized evolution of the INI format.

Does TOML support null values?

No, TOML intentionally does not support null/nil/None values. If a key is absent, it means the value is not set. This is a deliberate design choice to keep the format simple and unambiguous. If you need to represent "no value," simply omit the key entirely or use an empty string or a sentinel value in your application logic.

Can TOML files include or reference other TOML files?

No, the TOML specification does not support file includes, imports, or references. Each TOML file is self-contained. If you need to split configuration across files, that logic must be implemented in your application. Some tools like Hugo support config directories where multiple TOML files are merged automatically.

What file extension should I use for TOML files?

The standard file extension for TOML files is .toml. Well-known TOML files like Cargo.toml and pyproject.toml use this extension. Some tools use specific names without the .toml extension for historical reasons, but .toml is always recommended for new configurations.

How do I validate a TOML file?

You can validate TOML files using several methods: (1) Use Taplo, a TOML toolkit with a CLI validator and VS Code extension; (2) Use online validators like toml-lint; (3) Use language-specific libraries like toml (Python), toml-rs (Rust), or @iarna/toml (Node.js) to parse and catch errors; (4) Use our online TOML to YAML converter which will report parse errors.

Convert between TOML and YAML instantly with our free tool →

Convert between JSON and YAML with our free tool →

𝕏 Twitterin LinkedIn
Var dette nyttig?

Hold deg oppdatert

Få ukentlige dev-tips og nye verktøy.

Ingen spam. Avslutt når som helst.

Try These Related Tools

TYTOML ↔ YAMLY{}JSON ↔ YAML ConverterYMLYAML Validator & Formatter

Related Articles

JSON vs YAML vs TOML: Hvilket konfigformat bør du bruke?

Sammenlign konfigurasjonsformatene JSON, YAML og TOML.

YAML Syntaks & Validering: Vanlige feil og hvordan fikse dem

Mestr YAML-syntaks: innrykksregler, parsefeil, datatyper og beste praksis.