JSON Input

INI Output

Success
Warning

Going this direction means losing dimensions

Converting INI to JSON is mostly reading. Going the other way is fitting, and the fit is not always possible — which is the one thing a converter has to be honest about. JSON nests as deep as you like. INI has exactly two levels: a [section], and the keys inside it. There is no third, and no standard that could add one, because INI has never had a specification to add anything to.

You would think that makes this a niche page. It does not, because an enormous amount of software still reads this shape. Git's configuration files are INI with a subsection twist. Every systemd unit file is INI, right down to the [Unit] and [Service] headers. So is tox.ini, so is my.cnf, and so is the .editorconfig sitting in the root of most repositories you have cloned this year. If you are generating configuration for any of them from something that thinks in JSON, this is the shape you have to land on.

A nested object becomes a section. One level deeper becomes a dotted header — [database.primary] — which is as far as the format stretches, and even then only for parsers that agree on what a dot means. Deeper than that has nowhere to go, so those keys are listed in an amber notice under the output instead of being flattened into something that would read back as a different structure. A converter is allowed to change the format. It is not allowed to change the data and say nothing.

Arrays of simple values become repeated key[] = value lines. That bracket convention is not universal, so check it against whatever will read the file — the same array is written as one comma-separated line by some tools and as repeated bare key = lines by others. An array of objects has no representation at all and is reported rather than mangled.

Writing the file

  1. Paste the JSON, or open a fileIt has to be an object at the top level. An array or a bare string has no INI form — a config file is a set of named sections and named keys, and there is nothing to name an array's elements with.
  2. Pick the layoutSpacing chooses between key = value and key=value; both parse everywhere, and which one you want usually depends on the file you are matching. Align pads the keys within a section so the separators line up. Sort orders keys alphabetically, which is worth turning on if the file is going into version control and you would rather the diffs stayed small.
  3. Read the amber notice if one appearsIt names every key that nests past what INI can express. Nothing is silently dropped, and nothing is silently flattened — you get the path, and you decide whether to restructure the JSON or to accept the loss.
  4. Copy or downloadThe file is written with plain \n line endings. Feed it straight back through INI to JSON if you want to confirm the round trip before you deploy it.

Turn Sort on when the output is going into a repository. Two runs of a generator that iterates over an object in a different order produce two identical configs with a hundred-line diff between them, and reviewers stop reading the diff shortly afterwards.

What each JSON construct turns into

The top-level scalars land above the first header, in the implicit section every parser reads as the global one. network and sim become headers. The dns array becomes two dns[] lines. And the 19-digit iccid comes out with all 19 digits, because it is protected before parsing rather than after.

sim-provisioning.json → sim-provisioning.ini Round-trips cleanly
sim-provisioning.jsonNested objects, array, long integer
{
  "network": {
    "mcc": 234,
    "dns": ["10.4.0.53", "10.4.0.54"]
  },
  "sim": {
    "iccid": 8901240544102066246,
    "plan": "Unlimited 5G"
  }
}
sim-provisioning.iniTwo sections · repeated key[]
[network]
mcc = 234
dns[] = 10.4.0.53
dns[] = 10.4.0.54

[sim]
iccid = 8901240544102066246
plan = Unlimited 5G

Where this actually comes up

Generating a unit file or a service config

Your deployment templates are JSON or YAML and the thing you are deploying reads INI. Rather than a template full of string concatenation, keep the config as data and write it out at the end — the structure stays inspectable right up to the moment it becomes text.

Handing settings to a tool that predates JSON

Python packaging is full of this: pip reads its configuration from an INI file whose sections match the command names, and setup.cfg and tox.ini follow the same pattern. If a script assembles those settings, it almost certainly assembles them as a dictionary first.

Producing an .editorconfig from shared defaults

The EditorConfig format is INI with glob patterns as section names, so a team that keeps its house style as JSON can write the file out per repository instead of copying and hand-editing it.

Making a JSON payload readable to a human

INI is easier to skim than JSON for anything shallow: no braces, no quotes, no trailing-comma argument. If you are pasting a settings block into a ticket or a runbook, INI reads better — and JSON to Table is the other way to make a payload legible.

What it does

  • Deeply nested keys are named, not dropped. Anything past a dotted section header appears in an amber notice with its full path.
  • Arrays become repeated key[] lines, keeping their order, rather than being collapsed into one comma-separated value.
  • Long integers stay exact. A 19-digit identifier is protected before parsing, so it reaches the file with every digit — most converters round it at fifteen and report success.
  • Values that would break the format get quoted. A value containing =, a newline, or a leading bracket is escaped so the file parses back to the same data.
  • Line endings are always \n, so the same JSON produces the same file no matter what machine you ran it on.

Questions that come up

Why did my array of objects disappear?

Because there is nowhere to put it. "sim": [{"iccid": 1}, {"iccid": 2}] needs a repeated section — the thing TOML added [[table]] for — and INI has no equivalent. The keys are named in the notice rather than half-written. If you need repeated groups, JSON to TOML is the format that has them.

What happens to numbers and booleans?

They are written without quotes and become text, because every value in an INI file is text. Reading the file back gives you the string 30000 unless the parser is asked to type values — true, false and null are the exception and are recognised almost everywhere. INI to JSON has a toggle for exactly this, and its sample is this page's sample, so you can watch the round trip both ways.

Can I keep comments?

There are none to keep — JSON has no comment syntax, so nothing arrives to preserve. Going the other direction is where comments matter, and it is why INI Formatter rewrites the source text instead of parsing and reprinting: a parser returns values, and a comment is not part of a value.

My key has a dot in it. Will it become a section?

Not from here — a dot inside a key name is escaped on the way out so it reads back as one key. Section headers are the only place a dot is treated as nesting, and only because a fair number of parsers do that. If the tool reading your file treats dotted headers as literal names, the file still works; the names just look longer than you expected.

Does the output round-trip exactly?

Structure and values, yes, as long as nothing was reported in the notice. Types are the exception, for the reason above. The quickest check is the one you can run right now: convert the sample here, paste the result into INI to JSON, turn its typing toggle on, and compare it with what you started from.

Related tools

Worth reading