INI#
INI files are the longest-living config format on the
operator’s hosts. Key/value pairs grouped under bracketed
section headers, comments with ; or #, no formal spec
and no agreement on the edge cases. Windows shipped INI in
1985; configparser made it the Python standard for
config files; systemd unit files are INI in spirit; Git
config, MySQL my.cnf, pip.conf, php.ini, and most
.desktop entries are INI dialects.
Because there is no standard, every parser implements its own dialect. Two INI files that look identical can parse differently. Treat INI as a family of formats, not a single one.
Minimal example#
; comment (semicolon)
# comment (hash) — supported by most modern parsers
[DEFAULT]
timeout = 30
retries = 3
[server]
host = 0.0.0.0
port = 8080
tls = true
[database]
url = postgres://localhost/scan
pool = 16
Sections#
Sections are bracketed names. Every key/value pair that
follows belongs to the most recently declared section. Some
dialects allow nested sections via dotted names
([server.tls]); the spec-less core does not require this.
[section_name]
key1 = value1
key2 = value2
[another_section]
key1 = different_value
A pair before any section header lives in an implicit default
section (often named DEFAULT, global, or just
__no_section__ depending on the parser).
Key/value pairs#
The basic key = value form. Some dialects accept :
instead of =. Whitespace around the separator is usually
trimmed. Values are strings in the wire form; the parser
or the consumer is responsible for coercing.
host = 0.0.0.0
port = 8080
debug = true
retry_delay = 1.5
user_agent = MyScan/1.0
description = a longer line that the parser keeps as one string
Quotes are not standard; parsers either strip them or keep them depending on dialect. The operator avoids quoting unless the parser documentation says it strips quotes.
Multi-line values#
Some dialects (Python configparser) allow continuation
lines with leading whitespace. Many do not. Test with the
target parser.
description = a long description
that continues across
multiple lines
roles = admin
reader
writer
In Git config, the operator uses backslash-newline. In systemd unit files, multi-line values are not allowed at all; lines join with backslash continuation in shell-style strings only.
Common dialects#
The places the operator meets INI and how each one diverges from the spec-less core.
Dialect |
Notes |
|---|---|
Windows INI |
|
Python configparser |
|
systemd unit files |
|
Git config |
|
MySQL my.cnf |
|
pip.conf / requirements |
|
php.ini |
|
.desktop / FreeDesktop |
|
When the operator hits an unfamiliar .ini-flavoured file,
the first question is “which parser?” — that decides the
dialect.
Tooling#
Tool |
Notes |
|---|---|
|
The reference dialect for new INI work. Reads and writes. |
|
CLI to read, set, delete, and merge INI keys.
|
|
The canonical way to read and edit Git’s INI. |
|
Drop-in override editor for systemd unit INI. |
|
C-side parsers when embedding INI in firmware. |
|
Convert INI to YAML / JSON for further processing. |
$ crudini --set my.cnf mysqld bind-address 0.0.0.0
$ crudini --get my.cnf mysqld max_connections
$ crudini --del my.cnf mysqld old_setting
$ git config --global user.email "rk@example.com"
$ git config --get-all remote.origin.fetch
$ python -c "
import configparser
c = configparser.ConfigParser()
c.read('app.ini')
print(c.get('server', 'host'))
"
INI vs TOML vs YAML#
INI |
Untyped strings, no nesting, dialect-dependent. Use when the target tool requires it (Git config, systemd, Windows registry exports). |
|---|---|
TOML |
Typed values, real nesting, a spec. Pick for new
project config ( |
YAML |
Indentation-driven, anchors/aliases, complex types. Pick for human-edited configs with reused fragments (CI, k8s). |
INI is the format the operator keeps reading because legacy software writes it. It’s rarely the right choice for new configuration.
Pitfalls#
No standard. Two parsers can disagree on the same file. Always know which parser will read the file before writing one.
Type coercion. Values are strings in the wire. The reader interprets
true,1,yesdifferently across parsers; explicit is safer.Inline comments.
port = 8080 ; old portmay parse the entire8080 ; old portas the value. Put comments on their own line.Repeated keys. Some parsers keep the last value, some raise an error, some build a list (systemd). Behaviour is dialect-specific.
Section ordering. INI files are not ordered guarantees; most parsers preserve order on read/write, but the spec does not require it.
References#
Wikipedia: INI file, the closest thing to a unified reference.
systemd.unit(5), the systemd dialect.
TOML, the typed modern successor.
YAML, the indentation-driven alternative.
Comments#
Two conventions.
Marker
Notes
;Original Windows convention. Universally accepted.
#Unix-flavoured. Accepted by Python
configparser, Git config, most modern dialects.Inline comments (a
;after a value on the same line) are not universally supported. Pythonconfigparseracceptsinline_comment_prefixesonly when configured; many other parsers treat; …as part of the value.