TOML and INI files
Sections, dotted keys, typed values and arrays without ambiguity, plus why TOML replaced INI for tooling config and how to migrate a file between them.
TOML keeps the types
TOML is a config format with the ergonomics of INI and the type safety of JSON. Every value has an unambiguous type, and there is exactly one way to write it — which is exactly what YAML lacks.
title = "example"
version = "1.10" # string, always
port = 8080 # integer
ratio = 0.75 # float
enabled = true # boolean
date = 2026-09-18T10:00:00Z # native datetime
tags = ["a", "b"] # array
[server]
host = "0.0.0.0"
timeout = 30
[server.limits]
max_conn = 100 # nested table
[database]
host = "localhost"
# dotted key writes into the table above
database.port = 5432- Order of keys is preserved, so the file you write is the file you read.
- Arrays of tables use
[[name]]and are the idiomatic way to express a list of records. - Comments run to the end of the line with
#.
INI is a family, not a standard
; classic ini
[server]
host = 0.0.0.0
port = 8080
[database]
host = localhost
port = 5432| Feature | INI | TOML |
|---|---|---|
| Value types | All strings; the reader guesses | Explicit int, float, bool, date, array |
| Nesting | One level of sections | Arbitrary tables and arrays of tables |
| Duplicates | Often last-wins, silently | Defined behaviour per table |
| Specification | None — every parser differs | Versioned spec with a test suite |
| Interpolation | Some dialects support it (%s or brace syntax) | None; compose in code |
INI's flexibility is the problem: configparser, Windows GetPrivateProfileString and older tools disagree about quoting, comments and duplicate keys. Migrate to TOML when a real tool consumes the file.
Reading them in code
import tomllib # read-only, Python 3.11+
import configparser
with open("app.toml", "rb") as f:
cfg = tomllib.load(f) # must be opened in binary mode
print(cfg["server"]["port"]) # already an int
parser = configparser.ConfigParser()
parser.read("legacy.ini")
port = parser.getint("server", "port") # you must coerce by hand⚠️
In INI, boolean parsing is a known trap:
configparser.getboolean accepts only 1/yes/true/on and their negatives, so enabled = enable raises a ValueError at runtime. Validate config at startup rather than at first use.FAQ
Should config be TOML or YAML?
TOML when a human edits a small, typed file (tool config, project metadata). YAML when the structure is deep and tool-shaped, and JSON when it is generated.
Can TOML express an array of records?
Yes. Use
[[server]] blocks; each occurrence appends one record to the server array, which maps cleanly to a list of objects.Related
YAML for configuration Choosing a format: size, speed, readability and tooling
Last refreshed 2026-09-18.