File types · Explainer

The TOML file (.toml)

A TOML file is a plain-text configuration file made of key = value lines grouped under [table] headers, with real types for numbers, booleans and dates. This guide explains the syntax, the differences between TOML 1.0 and 1.1, the errors parsers report, and has free sample TOML files to download for testing.

At a glance

Full name
Tom's Obvious Minimal Language
Extensions
.toml
MIME type
application/toml, registered with IANA
Kind
Plain text (configuration data)
Encoding
UTF-8, required by the specification
Standard
TOML 1.1.0 (December 2025) at toml.io; TOML 1.0.0 (January 2021) is still the most widely supported
First released
2013, by Tom Preston-Werner
Data types
String, integer, float, boolean, four kinds of date and time, array and table
Comments
Yes, from # to the end of the line
Opens with
Any text editor or code editor
Magic number
None

The basics

What is a TOML file?

A TOML file stores configuration as text: key = value lines, grouped into tables by [headers], much like an INI file. The difference is that TOML has a written specification and real types. A value in quotes is a string, 8080 is an integer, true is a boolean and 2026-10-27 is a date, and a parser in any language must read them the same way.

Tom Preston-Werner, a co-founder of GitHub, created it in 2013 as a config format that is easy to read and maps unambiguously to a hash table, the dictionary or object type every language has. You meet it mostly as a project's own settings file:

FileUsed by
Cargo.toml, Cargo.lockRust: the package manifest and its lock file
pyproject.tomlPython packaging (PEP 518, 2016) and tool settings for Ruff, pytest, Black and others
uv.lockThe uv Python package manager's lock file
hugo.tomlThe Hugo static site generator
netlify.tomlBuild and redirect settings for Netlify
Project.toml, Manifest.tomlJulia packages and environments
libs.versions.tomlGradle version catalogues

In each case the file name is fixed by the tool, so a file called cargo.toml (lower case) or pyproject.TOML is simply not found on case-sensitive systems.

Anatomy

What's inside a TOML file

A TOML file is a list of key = value pairs. [table] headers group the pairs that follow them, and every value has an explicit type you can tell from how it's written. Here is a small but complete file, part by part.

config.toml
# Settings for a small web app
title = "Sample app"
version = "2.10"
debug = false
port = 8080
ratio = 0.75
released = 2026-10-27T09:30:00Z
languages = ["en", "nl"]
owner = { name = "Ada Example", email = "ada@example.com" }

[database]
host = "db.example.internal"
pool.max = 10

[database.replica]
host = "replica.example.internal"

[[servers]]
name = "web-1"

[[servers]]
name = "web-2"
  1. 1# Settings for a small web app

    A comment

    Everything from # to the end of the line is ignored, unless the # is inside a string.

  2. 2title = "Sample app"

    A key and a string

    Keys go on the left of =, values on the right. Strings always need quotes: unlike YAML or INI, a bare word is an error, not text.

  3. 3version = "2.10"

    A version kept as text

    Because strings are always quoted, "2.10" can never turn into the number 2.1, the classic YAML trap.

  4. 4debug = false

    A boolean

    Only lowercase true and false. yes, on and True are errors.

  5. 5port = 8080 ratio = 0.75

    An integer and a float

    Integers are 64-bit, may use _ as a separator (1_000_000) and may be written in hex, octal or binary (0xFF, 0o755, 0b1010). Floats need a digit on both sides of the point, and inf and nan are allowed.

  6. 6released = 2026-10-27T09:30:00Z

    A date and time

    A native type, written as in RFC 3339. This one is a moment in UTC; TOML also has local date-times without a time zone, plain dates and plain times.

  7. 7languages = ["en", "nl"]

    An array

    Values in square brackets, separated by commas. Arrays may span several lines and end with a trailing comma.

  8. 8owner = { name = …, email = … }

    An inline table

    A small table written on one line. In TOML 1.0 it must stay on one line, with no trailing comma; TOML 1.1 relaxes both rules.

  9. 9[database]

    A table header

    Starts a table: every key below it, up to the next header, belongs to database. Indenting the keys is allowed but means nothing.

  10. 10pool.max = 10

    A dotted key

    Creates nested tables on the fly: this is database.pool.max. Dotted keys and headers are two ways of writing the same structure.

  11. 11[database.replica]

    A sub-table

    A dotted header creates a table inside database. The parent doesn't need a header of its own.

  12. 12[[servers]]

    An array of tables

    Double brackets add a new table to the servers list each time they appear, the TOML way to write a list of records.

How it works

How TOML turns into data

A parser turns a TOML file into nested tables (dictionaries). The anatomy example above loads as this, shown as JSON, with Python's tomllib:

config.json
{
  "title": "Sample app",
  "version": "2.10",
  "debug": false,
  "port": 8080,
  "ratio": 0.75,
  "released": "2026-10-27 09:30:00+00:00",
  "languages": ["en", "nl"],
  "owner": { "name": "Ada Example", "email": "ada@example.com" },
  "database": {
    "host": "db.example.internal",
    "pool": { "max": 10 },
    "replica": { "host": "replica.example.internal" }
  },
  "servers": [{ "name": "web-1" }, { "name": "web-2" }]
}
  • Headers and dotted keys build the same tree. [database] followed by pool.max = 10 gives the same result as [database.pool] followed by max = 10.
  • Each key and each table can be defined once. Writing port twice in one table, or [database] twice, makes the whole file invalid. Arrays of tables ([[servers]]) are the exception: repeating them is the point.
  • Order of tables doesn't matter, but keys after a header always belong to that header. A top-level key placed below a table header ends up inside that table, a common mistake when adding settings to the end of a file.
  • Dates come back as date objects in languages that have them, such as Python's datetime. JSON has no date type, which is why the date above became a string.
The four kinds of strings
Written asNameEscapesUse for
"C:\\Users"BasicYes: \n, \t, \", \u00E9Most text
'C:\Users'LiteralNone: what you see is what you getWindows paths, regular expressions
"""…"""Multi-line basicYesLong text with escapes
'''…'''Multi-line literalNoneLong text, code, templates

Versions

TOML 1.0 and TOML 1.1

TOML went through several 0.x versions before 1.0.0, released on 11 January 2021, froze the core. 1.1.0, released on 18 December 2025, is a small step: every valid TOML 1.0 file is still valid, and it accepts a few things 1.0 rejects:

  • Inline tables may span several lines and end with a trailing comma.
  • Two new escapes in basic strings: \e for the escape character and \xHH for a code point up to 255.
  • Seconds are optional in times and date-times: 03:15 and 2026-11-01T02:00.
  • Clarifications, including that parsers may support integers and floats beyond 64 bits.
owner.toml
# TOML 1.0: an inline table must fit on one line
owner = { name = "Ada Example", email = "ada@example.com" }

# TOML 1.1: it may span lines and end with a comma
owner = {
  name = "Ada Example",
  email = "ada@example.com",
}

Support is arriving gradually. Python's tomllib reads TOML 1.1 from Python 3.15 (released October 2026); on Python 3.11 to 3.14 it reads 1.0 only and rejects the multi-line inline table above. Of the parsers we tested, tomli 2.5.0, tomlkit 0.15.2 and smol-toml 1.9.1 for JavaScript read sample-toml-1.1.toml; the tomllib in Python 3.13 stops at its first line of content.

Which version should you write?

Stick to TOML 1.0 syntax in files other people's tools will read, such as pyproject.toml or Cargo.toml, until you know every tool involved supports 1.1. A 1.0 file works everywhere.

Comparison

TOML vs YAML, JSON and INI

TOML[YAML](/file-types/yaml)[JSON](/file-types/json)[INI](/file-types/ini)
Structure from[tables] and key = valueIndentationBrackets and braces[sections] and key = value
SpecificationYes: TOML 1.1.0Yes: YAML 1.2.2Yes: RFC 8259None; every parser has its own dialect
CommentsYes, #Yes, #NoYes, ; and often #
TypesExplicit: quotes for strings, few and strictGuessed from the text, version-dependentFew and strictEverything is text
DatesNative date and time typesTimestamps in many parsersNone; strings by conventionNone
Deep nestingPossible, but long [a.b.c] headers get awkwardNaturalNaturalUsually two levels: section and key
Typical useApp and package config: pyproject.toml, Cargo.tomlConfig people edit: CI, Kubernetes, ComposeAPIs, data exchange, generated configOlder and Windows software, php.ini, Git-style config

TOML's strictness is the point: there is no Norway problem, because NO without quotes is an error, not false. The price is that it suits flat or moderately nested settings better than deep trees. For large nested documents, such as Kubernetes manifests, YAML or JSON is the usual choice.

Troubleshooting

Why won't my TOML file load?

TOML parsers stop at the first problem and report the line and column. The messages below are from Python's tomllib; other parsers word them differently but catch the same mistakes.

Written asErrorFix
name = helloInvalid valueQuote strings: name = "hello"
debug = True or debug = yesInvalid valueBooleans are lowercase true or false only
port = 1 twice in a tableCannot overwrite a valueRemove the duplicate key
[database] twiceCannot declare ('database',) twiceMerge the two tables, or use [[database]] if you meant a list
path = "C:\Users\ada"Invalid hex value\U starts an escape. Use a literal string: 'C:\Users\ada'
id = 01Expected newline or end of document after a statementNo leading zeros in integers; quote IDs and postcodes
A file saved with a UTF-8 BOMInvalid statement (at line 1, column 1)Save as UTF-8 without BOM. smol-toml accepts the BOM; tomllib and tomli don't
A multi-line inline tableInvalid initial character for a key partThe parser supports TOML 1.0 only: put the table on one line, or use a [table] header

If the file loads but the settings have no effect, look at where they sit. A key added at the bottom of the file belongs to the last table header above it, not to the top level.

How to

How to open, edit and convert a TOML file

  • Open and edit it: any text editor works on Windows, macOS, Linux or a phone. In VS Code, an extension based on Taplo, such as Even Better TOML, adds highlighting, formatting and validation, including schemas for pyproject.toml and Cargo.toml.
  • Let the tool edit it: cargo add serde updates Cargo.toml, and uv add httpx or poetry add httpx updates pyproject.toml, keeping the formatting and comments.
  • Read it from code: Python has tomllib in the standard library since 3.11. It reads only; write with tomli-w, or edit while keeping comments with tomlkit. In Rust, the toml crate works with serde; in JavaScript, smol-toml reads and writes.
  • Convert to JSON: load it and write JSON, as below. Comments are lost, and dates need converting to strings.
toml_to_json.py
import json, tomllib

with open("config.toml", "rb") as f:   # tomllib wants binary mode
    data = tomllib.load(f)

print(json.dumps(data, indent=2, default=str))   # dates become strings

Security

Is a TOML file safe? Secrets and build files

Parsing TOML is safe: unlike YAML, it has no tags that ask the parser to build objects, so loading a file can't run code. The risks are in what the files contain and what tools do with them:

  • Secrets in config files. API keys and passwords in a committed config.toml or netlify.toml, or in a shared link, are a common leak. Keep them in environment variables or a secrets manager. Cargo stores your registry token separately, in credentials.toml in the Cargo home folder, so that Cargo.toml can be shared safely.
  • Build files name code to run. Installing a Python package from source makes pip run the build backend named in its pyproject.toml, and Cargo runs a crate's build.rs. Reading those TOML files is harmless; building the project means trusting it.
  • Size limits. Parsers load the whole file into memory. Services that accept TOML uploads should cap their size.

Free downloads

Sample TOML files to download

Free sample TOML files for testing parsers, config loaders, editors and upload limits. All except sample-toml-1.1.toml are valid TOML 1.0 and load in Python's tomllib, tomli, tomlkit and smol-toml.

sample-config.toml · 2.3 KBDownloadOpen
Loading…

What's inside sample-config.toml

The file is commented: each numbered comment marks one of these parts.

  1. Comments 1 to 4: root keys and simple values

    Strings, a quoted version number, a boolean, integers with underscores and in octal, a float and inf.

  2. Comment 5: dates and times

    All four kinds: an offset date-time, a local date-time, a local date and a local time.

  3. Comments 6 and 7: strings

    A basic string with \", \t and \u00e9 escapes, literal strings for a Windows path and a regular expression, and a multi-line string.

  4. Comments 8 and 9: arrays and an inline table

    A one-line array, a multi-line array with a trailing comma, and an owner inline table.

  5. Comments 10 to 12: tables

    A [database] table, dotted keys that create database.pool, and a [database.replica] sub-table.

  6. Comment 13: quoted keys

    Keys with a space, an accent and a dot, which need quotes.

  7. Comment 14: an array of tables

    Two [[servers]] entries that load as a list of two tables.

All sample TOML files

  • Commented config file

    sample-config.toml · 2.3 KB (2,359 bytes)

    An app configuration with 14 numbered comments covering every value type, all four date and time types, the four kinds of strings, tables, dotted keys, quoted keys and an array of tables.

    • Teaching the parts of a TOML file
    • Testing config loaders and type handling
  • pyproject.toml for a fictional package

    sample-pyproject.toml · 1.3 KB (1,355 bytes)

    Packaging metadata in the standard [build-system] and [project] tables, with dependencies, optional dependencies, a script entry point and [tool.*] settings for Ruff and pytest.

    • Testing tools that read `pyproject.toml`
    • A starting point for a new Python package
  • Cargo.toml for a fictional crate

    sample-cargo.toml · 1.0 KB (1,056 bytes)

    A Rust manifest with dependencies as strings and inline tables, dev-dependencies, features, a [[bin]] array of tables and a release profile. Rename it to Cargo.toml to use it.

    • Testing tools that read Cargo manifests
    • Seeing inline tables and arrays of tables in real use
  • TOML 1.1 features (rejected by 1.0 parsers)

    sample-toml-1.1.toml · 859 bytes

    A multi-line inline table with a trailing comma, the new \e and \xHH escapes and times without seconds. Valid TOML 1.1.0; a parser that supports only 1.0 should report an error.

    • Finding out which TOML version a parser supports
    • Testing error reporting
  • Non-ASCII text with CRLF line endings

    sample-unicode-crlf.toml · 794 bytes

    Greetings in eight scripts and emoji, the same characters as \u and \U escapes, quoted keys such as "€", and a multi-line string, saved with Windows line endings.

    • Spotting encoding bugs
    • Checking CRLF handling in multi-line strings
  • 100 KB TOML file

    sample-100kb.toml · 100 KB (102,400 bytes)

    714 fictional sensors as an array of tables, padded with a final comment to exactly 102,400 bytes.

    • Upload and size-limit tests
    • Parser performance

Ways to test with them

  • Which version your parser supports: load sample-toml-1.1.toml. An error at the owner table means TOML 1.0 only.
  • Types: load sample-config.toml and check that version is a string, permissions is 493, timeout is infinity and launch_day is a date.
  • Line endings: in sample-unicode-crlf.toml, notes.text should come back as two lines; check whether your parser keeps the CR.
  • Upload limits: sample-100kb.toml is exactly 102,400 bytes, for testing a limit at the boundary.

Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.

Put it online

Have a TOML file? Give it a link.

Drop a TOML file on 99helpers and it gets its own address, for sharing a config example or a test fixture. Opened in a browser, the link shows the file as plain text, and scripts can fetch it from the same link.

Questions

TOML files, frequently asked

What does TOML stand for?

Tom's Obvious Minimal Language, after its creator, Tom Preston-Werner.

How do I open a TOML file?

With any text editor, such as Notepad, TextEdit in plain-text mode or VS Code. A TOML extension in your editor adds highlighting and error checking.

Is TOML better than YAML?

For hand-edited settings, TOML is harder to get wrong: strings need quotes and nothing is guessed. YAML is better at deeply nested data and is the norm for CI and Kubernetes. Use what the tool expects.

What is the difference between TOML and INI?

They look alike, but INI has no specification and treats every value as text, so parsers disagree. TOML has a spec, types and nesting, so every compliant parser reads a file the same way.

Which TOML version is current?

TOML 1.1.0, released in December 2025. Many parsers still support only 1.0.0 (2021), so files meant for others should stick to 1.0 syntax.

How do I read a TOML file in Python?

Use tomllib from the standard library (Python 3.11 and later): open the file in binary mode and call tomllib.load(f). To write TOML, use tomli-w or tomlkit.

Can a TOML file have comments?

Yes. Everything after # on a line is a comment, unless the # is inside a string.

How do I convert TOML to JSON?

Load it with a TOML library and write it out with a JSON library. Comments are lost, and dates must be turned into strings because JSON has no date type.

Related formats

Other file types explained

Keep going

Related

Sources

Last reviewed 27 October 2026.