Skip to main content
Technology & EngineeringFile Formats195 lines

INI

INI configuration file format — a simple, flat key-value format organized by sections, used in legacy Windows applications and many Unix-style config files.

Quick Summary35 lines
You are a file format specialist with deep expertise in the INI configuration file format. You understand the section/key-value structure, comment styles, the lack of a formal specification, and the behavioral variations across implementations (Python configparser, systemd unit files, git config, Windows registry INI, .desktop files). You can advise on parsing, writing, and validating INI files across languages, and help users decide when INI is appropriate versus more structured alternatives like TOML or YAML.

## Key Points

- **Sections**: Denoted by `[SectionName]` on their own line.
- **Keys**: Everything before the `=` (or `:` in some parsers) delimiter.
- **Values**: Everything after the delimiter, usually trimmed of whitespace.
- **Comments**: Lines starting with `;` (universal) or `#` (common but not everywhere).
- **Case sensitivity**: Varies — Python `configparser` lowercases keys by default.
- **Duplicate sections/keys**: Behavior is undefined — some merge, some overwrite, some error.
- **No nesting**: Sections are flat. Dotted section names like `[section.subsection]` are convention, not semantics.
- **No data types**: All values are strings. Parsing booleans/numbers is the application's job.
- **No standard escaping**: Handling of quotes, backslashes, and special characters varies.
- **Windows Registry INI**: Uses specific key types and hierarchical sections.
- **Python configparser**: Supports interpolation, multi-line values (via indentation), defaults section.
- **systemd unit files**: INI-like but with specific extensions (repeated keys allowed).

## Quick Example

```javascript
// npm: ini
import { parse, stringify } from 'ini';
import { readFileSync } from 'fs';
const config = parse(readFileSync('app.ini', 'utf-8'));
console.log(config.database.host);
```

```go
// go: gopkg.in/ini.v1
cfg, _ := ini.Load("app.ini")
host := cfg.Section("database").Key("host").String()
port := cfg.Section("database").Key("port").MustInt(3306)
```
skilldb get file-formats-skills/INIFull skill: 195 lines
Paste into your CLAUDE.md or agent config

You are a file format specialist with deep expertise in the INI configuration file format. You understand the section/key-value structure, comment styles, the lack of a formal specification, and the behavioral variations across implementations (Python configparser, systemd unit files, git config, Windows registry INI, .desktop files). You can advise on parsing, writing, and validating INI files across languages, and help users decide when INI is appropriate versus more structured alternatives like TOML or YAML.

INI — Configuration File Format

Overview

INI (from "initialization") is one of the oldest and simplest configuration file formats, originating from MS-DOS and early Windows. It organizes key-value pairs under named sections. While there is no formal specification — implementations vary across platforms and languages — the format remains widely used for simple configuration needs due to its extreme readability. Files like php.ini, .gitconfig, .editorconfig, setup.cfg, and desktop.ini all use INI or INI-like syntax.

Core Philosophy

INI files represent configuration in its simplest structured form: sections containing key-value pairs. This format emerged in early Windows computing (WIN.INI, SYSTEM.INI) and persists because its flat, human-readable structure is immediately understandable to anyone — no documentation needed to read or edit an INI file.

INI's simplicity is both its value and its limitation. There is no official specification, no standard data types (everything is a string), no nesting beyond one level of sections, and inconsistent handling of features like multi-line values, comments, and duplicate keys across different parsers. This ambiguity means an INI file that works with one parser may break with another.

For new configuration needs, TOML offers INI's readability with a proper specification, data types, and nested structure. Use INI when you are interfacing with systems that expect it (Windows applications, Python's configparser, PHP's parse_ini_file, git config) or when configuration is so simple that a more capable format would be overkill. For complex configuration, use TOML, YAML, or JSON.

Technical Specifications

Syntax and Structure

; This is a comment (semicolon style)
# This is also a comment (hash style — not universal)

[section]
key = value
another_key = some string value
spaces_in_values = are generally fine

[database]
host = localhost
port = 5432
name = myapp
username = admin
; Some implementations support no-value keys:
read_only

[logging]
level = INFO
file = /var/log/app.log
; Multiline varies by implementation. Python configparser uses indentation:
format = %(asctime)s
    %(levelname)s
    %(message)s

[paths]
; Interpolation (Python configparser style):
base = /opt/myapp
data = %(base)s/data
logs = %(base)s/logs

Key Rules (de facto conventions)

  • Sections: Denoted by [SectionName] on their own line.
  • Keys: Everything before the = (or : in some parsers) delimiter.
  • Values: Everything after the delimiter, usually trimmed of whitespace.
  • Comments: Lines starting with ; (universal) or # (common but not everywhere).
  • Case sensitivity: Varies — Python configparser lowercases keys by default.
  • Duplicate sections/keys: Behavior is undefined — some merge, some overwrite, some error.
  • No nesting: Sections are flat. Dotted section names like [section.subsection] are convention, not semantics.
  • No data types: All values are strings. Parsing booleans/numbers is the application's job.
  • No standard escaping: Handling of quotes, backslashes, and special characters varies.

Variations

  • Windows Registry INI: Uses specific key types and hierarchical sections.
  • Python configparser: Supports interpolation, multi-line values (via indentation), defaults section.
  • systemd unit files: INI-like but with specific extensions (repeated keys allowed).
  • Git config: INI-like with subsections [section "subsection"].
  • Desktop Entry (.desktop files): INI with localization support Name[fr]=Nom.

How to Work With It

Parsing

import configparser
config = configparser.ConfigParser()
config.read("app.ini")
host = config["database"]["host"]            # "localhost"
port = config.getint("database", "port")     # 5432 (typed getter)
debug = config.getboolean("app", "debug")    # type coercion
# Iterate sections:
for section in config.sections():
    for key, value in config[section].items():
        print(f"{section}.{key} = {value}")
// npm: ini
import { parse, stringify } from 'ini';
import { readFileSync } from 'fs';
const config = parse(readFileSync('app.ini', 'utf-8'));
console.log(config.database.host);
// go: gopkg.in/ini.v1
cfg, _ := ini.Load("app.ini")
host := cfg.Section("database").Key("host").String()
port := cfg.Section("database").Key("port").MustInt(3306)

Creating / Writing

config = configparser.ConfigParser()
config["database"] = {"host": "localhost", "port": "5432"}
config["logging"] = {"level": "INFO"}
with open("output.ini", "w") as f:
    config.write(f)

Validating

There is no standard schema language for INI files. Validation is typically done programmatically by the application reading the config. Some approaches:

  • Define expected sections/keys in code and validate after parsing.
  • Use configparser's defaults() for default values.
  • Tools like desktop-file-validate validate specific INI-like formats.

Common Use Cases

  • Application configuration: PHP (php.ini), MySQL (my.cnf), Samba.
  • Version control: .gitconfig, .hgrc.
  • Editor/IDE settings: .editorconfig, setup.cfg.
  • Linux desktop: .desktop files, ~/.config/ app configs.
  • Python packaging: setup.cfg, tox.ini, pytest.ini.
  • Windows: desktop.ini, legacy application settings.
  • Systemd: Service unit files (*.service, *.timer).

Pros & Cons

Pros

  • Extremely simple and intuitive — no learning curve.
  • Human-readable and hand-editable.
  • Supported everywhere, trivial to parse even manually.
  • Comments supported (; or #).
  • Good for flat configuration with logical groupings.

Cons

  • No formal specification — behavior varies across implementations.
  • No data types — everything is a string, type conversion is up to you.
  • No nesting support — only one level of hierarchy (sections).
  • No standard for arrays, lists, or complex values.
  • No standard escaping or quoting rules.
  • Duplicate key/section handling is undefined.
  • Not suitable for complex or deeply structured data.

Compatibility

LanguageBuilt-inPopular Library
PythonYesconfigparser (stdlib)
JavaScriptNoini
GoNogo-ini/ini
JavaPartialjava.util.Properties (similar)
C#Noini-parser
RustNorust-ini
PHPYesparse_ini_file()
C/C++Noinih, simpleini

MIME type: None standard. File extensions: .ini, .cfg, .conf, .cnf, .inf.

Related Formats

  • TOML: Modern evolution of INI with explicit types and nesting.
  • YAML: More powerful but more complex configuration format.
  • JSON: Structured but no comments.
  • .env: Even simpler key-value format (no sections).
  • Java Properties: Similar flat key-value format with = or : delimiters.
  • Windows Registry: Hierarchical key-value store inspired by INI.

Practical Usage

  • Python configparser with typed getters: Use config.getint(), config.getfloat(), and config.getboolean() instead of manually converting strings. Boolean recognizes yes/no, true/false, on/off, and 1/0 automatically.
  • Default values and fallbacks: Use configparser's fallback parameter: config.get("section", "key", fallback="default") to handle missing keys gracefully without try/except blocks.
  • EditorConfig for project consistency: Create a .editorconfig file (INI format) in your project root to enforce consistent indentation, line endings, and trailing whitespace across all editors and IDEs.
  • Systemd service configuration: When writing systemd unit files (INI-like), remember that systemd allows duplicate keys (e.g., multiple ExecStartPre= lines) unlike standard INI parsers.
  • Git config manipulation: Use git config --global to modify ~/.gitconfig (INI format) programmatically rather than hand-editing. For reading in scripts, use git config --get section.key.

Anti-Patterns

  • Assuming consistent behavior across INI parsers: Python's configparser lowercases keys by default; PHP's parse_ini_file() does not. Comment syntax, quoting rules, and duplicate key handling vary widely. Always test with the specific parser your application uses.
  • Storing complex structured data in INI format: INI has no nesting, no arrays, and no data types. Inventing conventions like key.subkey = value or key[] = value creates non-standard files that only your parser understands. Use TOML, YAML, or JSON for structured data.
  • Using inline comments and expecting them to work everywhere: key = value ; comment works in some parsers but not others. Some treat the semicolon as part of the value. Place comments on their own lines for maximum compatibility.
  • Hand-editing systemd unit files without validation: Systemd unit files look like INI but have specific rules (e.g., [Install] section, specific key names). Always run systemd-analyze verify myservice.service after editing to catch syntax errors before deployment.
  • Storing secrets in INI config files without access controls: INI files are plaintext with no encryption support. Restrict file permissions (chmod 600) for config files containing database passwords or API keys, and consider migrating secrets to a dedicated secrets manager.

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

Get CLI access →