XConvert
Downloads
Pricing

Format INI Online

Format and clean up INI configuration files to make them easier to read, edit, and share—right in your browser.

INI input99 chars · 8 lines
Formatted output

How to Format an INI File Online

  1. Paste Your INI Content: Drop your INI into the input panel — a legacy desktop.ini, a php.ini, a systemd unit file, a .gitconfig, an .editorconfig, a Python ConfigParser file, or any [section]/key=value snippet. The parser handles UTF-8 input including dotted-name sections, quoted Git subsections, and backslash-continued lines.
  2. Click Format: The formatter normalises whitespace around =, indents key/value lines under their [section] header, separates sections with a single blank line, and aligns inline comments. Section order and key order are preserved by default so diffs only show real changes.
  3. Review Inline Error Messages (Optional): If a line is malformed — unbalanced brackets in a section header, a key without a value, an unterminated quoted Git subsection — the formatter flags the offending line. Fix in place and re-format.
  4. Copy or Download: Click Copy to put the cleaned INI on your clipboard or Download to save a .ini file. Everything runs in your browser session — no upload, no signup, no telemetry.

Why Format an INI File?

The INI file format has no single official specification — it grew out of Microsoft Windows WIN.INI in the 1980s, was adopted by countless apps, and each implementation evolved its own quirks. That's exactly why a normalising formatter is useful: a file that one parser accepts may trip another over a stray comment marker, an unquoted Git subsection, or inconsistent whitespace. Formatting catches these issues before they hit a deployment.

  • Tame legacy Windows configs — desktop.ini, boot.ini-style files, and many old installer scripts use the classic Windows dialect: [Section] headers, key=value lines, and ; for comments. The Windows API's GetPrivateProfileString requires comments on lines by themselves, so a formatter that aligns comments to their own line keeps these files compatible.
  • Clean up php.ini, my.cnf, and redis.conf — Long-running services bundle their config as INI-style text with hundreds of key=value directives across [mysqld], [client], or [Session]-style sections. Formatting groups directives under their headers and removes accumulated whitespace drift after months of hand edits.
  • Normalise .gitconfig and .gitmodules — Git uses an INI flavour with quoted subsections: [remote "origin"], [branch "main"], [submodule "vendor/lib"]. Subsection names are case-sensitive (unlike the [section] part). A formatter that preserves the quoted form avoids subtle bugs where [remote "Origin"] and [remote "origin"] reference different remotes.
  • Tidy systemd unit files — systemd's .service, .timer, .socket, and .mount files use INI syntax inspired by the XDG Desktop Entry spec: [Unit], [Service], [Install] sections with Key=Value directives, no quotes around values, and line continuation via trailing backslash. Formatting these makes overrides via systemctl edit cleaner to review.
  • Validate Python ConfigParser output — Python's configparser accepts both = and : as the key-value delimiter and both ; and # as comment markers by default. Round-tripping a file through configparser.write() then formatting it here is a quick way to check the result before committing.
  • Diff-friendly review on PRs — Whitespace drift inside long INI files (tox.ini, pytest.ini, setup.cfg, .editorconfig) makes git diffs unreadable. Formatting before commit means reviewers see only behavioural changes, not trailing-space churn.

INI Dialect Comparison

Dialect Section format Comments Delimiter Line continuation Other quirks
Classic Windows (WIN.INI, desktop.ini) [Section] ; only; comments must be on their own line per GetPrivateProfileString = only Not supported Section/key names case-insensitive; values are strings
Python configparser [Section] # or ; as full-line prefixes (configurable); inline comments off by default = or : Multi-line values via deeper indentation, not \ Section names case-sensitive; keys lowercased by default; flat — no real nesting
Git config (.gitconfig) [section] and [section "subsection"] (subsection in double quotes) ; or # to end of line = Trailing backslash folds the next line Subsection names case-sensitive; section/variable names case-insensitive; supports [include] path = ... directives
systemd unit files [Unit], [Service], [Install] ; or # at line start = (no whitespace around = allowed before the value) Trailing \ joins the next line Values unquoted; same Key= can repeat to append; section/key names case-sensitive
.editorconfig [glob-pattern] (e.g., [*.{js,py}]) ; or # = Not in spec Section header is a glob, not a name; properties like indent_style, indent_size
Generic INI (no formal spec) [Section] Either ; or # depending on parser = or : depending on parser Parser-defined No standardised nesting — [a.b] is convention only

INI vs TOML vs YAML for Configuration

Property INI TOML YAML
Spec status No official spec — dialect-defined TOML 1.0.0 (Jan 11, 2021), 1.1.0 (Dec 2025) YAML 1.2.2 (Oct 2021)
Native datatypes None — every value is a string; the reader parses to bool/int String (4 variants), int (dec/hex/oct/bin), float, bool, 4 datetime variants, array, table String, int, float, bool, null, sequence, mapping (with implicit coercion in 1.1)
Nested structures Flat — convention [parent.child] is just a section name with a dot in it Tables, inline tables, arrays of tables, dotted keys for nesting Arbitrary nesting via indentation
Whitespace significance None (inside the line) None inside tables Significant — wrong indent breaks parsing
Comments ; and/or # depending on dialect # to end of line # to end of line
Multi-line values Backslash continuation (Git, systemd) or indent (configparser) Triple-quoted strings (""" or ''') Block scalars (|, >)
Quoting required No — values are bare strings Strings must be quoted; bare tokens reserved for literals Mostly optional — but unquoted no, on, yes may parse as booleans (Norway problem in 1.1)
Typical use Flat per-app config in scripts and daemons (php.ini, my.cnf, systemd) Typed nested config for tooling (Cargo.toml, pyproject.toml, hugo.toml) CI/CD, Kubernetes, Ansible — anywhere you need deep nesting
Best fit Legacy systems, simple flat config, small [section]/key=value files New projects needing types + nesting without indent pitfalls Deeply structured manifests where readability of trees matters

Frequently Asked Questions

Is there an official INI file specification?

No. INI grew out of Microsoft Windows configuration files in the 1980s and was never standardised by an SDO. The closest thing to a reference is the behaviour of the Windows API functions GetPrivateProfileString / WritePrivateProfileString, but every parser since has added or trimmed features — Python's configparser, Git's config code, systemd's unit-file parser, and PHP's parse_ini_file all behave differently on edge cases like comment markers, line continuation, and quoting. That's why this formatter is conservative: it normalises whitespace and structure without inventing syntax that some parsers would reject.

Can INI sections be nested?

Not in any formal sense. The square-bracket section header is a flat namespace — [database] and [database.replica] are two unrelated sections as far as the spec is concerned, even though many tools use the dot as a visual hint of hierarchy. Python's configparser explicitly stores sections in a flat dict; dotted names are just naming convention. If you need real nesting move to TOML (which has tables, inline tables, and dotted keys with proper semantics) or YAML. For Git config specifically, the [section "subsection"] form with a quoted subsection is the closest INI gets to a two-level hierarchy.

Does INI do any type coercion?

No — every value is a string at the file-format level. The reading library is responsible for parsing port=8080 as an integer or enabled=true as a boolean. Python's configparser exposes this with explicit getint(), getfloat(), and getboolean() methods (the boolean parser recognises yes/no, on/off, true/false, 1/0). PHP's parse_ini_file auto-coerces some literal tokens (true, false, null, yes, no) when called in INI_SCANNER_TYPED mode and leaves everything as a string otherwise. Don't assume types survive a round trip through any INI parser — explicit conversion in your code is the only safe bet.

; vs # for comments — which should I use?

It depends on what's going to read the file. Classic Windows .ini files use ; exclusively, and that's still the safest default for any consumer that targets the Windows API. Python's configparser accepts both # and ; as full-line comment prefixes by default. Git's config parser accepts both. systemd's parser accepts both. If you're writing for a known target, follow that project's convention — php.ini uses ;, redis.conf uses #, .gitconfig typically uses ;. If you're authoring a portable config consumed by a tool you don't control, prefer ; for the broadest compatibility. Inline comments (key = value ; trailing comment) are particularly dialect-sensitive — many parsers including default configparser don't strip them, so the comment becomes part of the value.

Does INI support multi-line values?

Yes, but the mechanism varies by dialect. Git config and systemd join a line ending in \ with the next line (and replace the backslash with a space, in systemd's case). Python's configparser uses a different approach: a value continues onto the next line as long as that next line is indented more deeply than the first line of the value — no backslash needed. Classic Windows INI has no documented multi-line mechanism, so values that need newlines are typically escaped with literal \n and unescaped by the application. Quoted strings spanning lines are not part of the common INI core and shouldn't be relied on.

Why does Git config wrap subsections in double quotes?

Git uses INI as its config format but needed a second level of namespacing — one for the section type (remote, branch, submodule, url) and one for the specific instance (the remote name, the branch name, the URL pattern). The standard syntax is [remote "origin"] with the subsection in double quotes, separated from the section name by a space. Subsection names are case-sensitive while the outer section name is case-insensitive, and double quotes plus backslashes inside the subsection name must be escaped (\" and \\). Git also supports a deprecated [section.subsection] dotted form for compatibility, but the quoted form is what git config --edit writes. The [include] section is special — Git follows path = ... directives inside it to load additional config files.

When should I use INI vs TOML?

Use INI when (a) you're maintaining an existing INI-format file that downstream tools already parse, (b) the config is genuinely flat — sections of key=value strings with no nesting or typed values needed, or (c) you're writing for a runtime that only ships an INI parser (legacy Windows apps, older PHP code, embedded scripts). Use TOML when you're starting a new project and want typed values (int, float, bool, datetime), real nested tables, arrays of tables, and a single official spec that every modern parser implements the same way. The Rust, Python, and Go ecosystems have all standardised on TOML for new tooling (Cargo.toml, pyproject.toml, hugo.toml) precisely because INI's dialect drift and string-only values became painful at scale.

What about .editorconfig files — are those INI?

Yes, .editorconfig uses INI syntax but with one twist: the section header is a glob pattern for matching files, not a name. [*.py], [*.{js,ts,jsx,tsx}], and [Makefile] are all valid section headers, and the properties inside (indent_style = space, indent_size = 2, end_of_line = lf, charset = utf-8, trim_trailing_whitespace = true, insert_final_newline = true) apply to any file matching that glob. The root = true property at the top of a file tells the editor to stop searching parent directories for further .editorconfig files. This formatter handles .editorconfig files cleanly — section headers are preserved verbatim including the glob characters.

Is anything uploaded to your servers?

No. The INI Formatter runs entirely in your browser — your file never leaves the tab. There are no network requests after the initial page load, so secrets that often live in INI files (database passwords in my.cnf, API tokens in tool configs, OAuth client IDs in .gitconfig) stay on your machine. The page also works offline once loaded. If you also work with JSON or YAML, the JSON Formatter, YAML to JSON, and Validate YAML tools run the same way.

Related Format tools
Toml FormatterProperties FormatterEnv FormatterHcl FormatterGraphql FormatterJson Formatter

Image Tools

Image CompressorCompress JPEGCompress PNGCompress GIFCompress WebPImage ConverterJPG ConverterImage Resizer

Video Tools

Video CompressorCompress MP4MP4 to GIFVideo to GIFVideo ConverterMP4 ConverterVideo Cutter

Audio Tools

Audio CompressorCompress MP3Compress WAVAudio ConverterMP3 ConverterFLAC to MP3Audio Cutter

Document Tools

Compress PDFMerge Images to PDFSplit PDFPDF to JPGUnzip FilesRAR Extractor
© 2026 XConvert.com. All Rights Reserved.
About UsPrivacy PolicyTerms of ServiceContactHelp Us Grow