---
url: https://findutils.com/guides/ini-to-json
title: "How to Convert an INI File to JSON"
description: "Convert .ini, .cfg and .conf files to nested JSON. Read how sections map to objects, why values stay strings, and what happens to comments and duplicate keys."
category: developer
content_type: guide
guide_type: subtopic
cluster: config
locale: en
read_time: 8
status: published
author: "olgunozoktas"
published_at: 2026-09-16T12:00:00Z
excerpt: "INI never had a standard, so every converter has to say which rules it follows. Read how [section] headers become nested objects, why 8080 stays a string, and which JSON shapes cannot be written back as INI."
tag_ids: ["config", "ini", "json", "data-conversion"]
tags: ["Config", "INI", "JSON", "Data Conversion"]
primary_keyword: "convert ini to json"
secondary_keywords: ["ini to json converter", "cfg to json", "conf to json", "php.ini to json", "json to ini", "parse ini file"]
tool_tag: "ini-json-converter"
related_tool: "ini-json-converter"
related_tools: ["ini-json-converter", "properties-json-converter", "env-json-converter", "json-toml-converter", "json-formatter"]
og_image: "/images/content/guides/ini-to-json-cover-20260916.webp"
image_alt: "Blank cream cards sorted into the separate compartments of an oak organiser beside a ceramic tray where the same cards sit in nested, stacked groups."
updated_at: "2026-09-16T12:00:00Z"
---

Convert an INI file to JSON when a script, a schema check or a diff tool needs structured data and the config is still written as `[section]` blocks. FindUtils [INI JSON Converter](/developers/ini-json-converter/) reads `.ini`, `.cfg` and `.conf` text and writes nested JSON, and writes `[section]` blocks back from a JSON object. The file is read in the browser and nothing is uploaded.

This guide explains which INI rules the converter follows, how sections become objects, why values stay strings, what happens to comments and duplicate keys, and which JSON shapes cannot be written back as INI.

## Why Is Converting INI Harder Than It Looks?

INI has no specification. Every program that reads one invented its own rules, so a converter that does not say which rules it follows is guessing on your behalf.

The disagreements are real and they change the output:

- **Comment characters.** Some readers accept only `;`. Others accept `#` too. Java-style `.properties` uses `!`.
- **Separators.** `key = value` is universal, `key: value` is common, and plain whitespace works in some dialects.
- **Quoting.** Some readers strip surrounding quotes, others treat them as part of the value.
- **Duplicate keys.** Most readers keep the last value. A few collect repeats into a list.
- **Dotted headers.** `[a.b]` is a section literally named `a.b` in most readers, and a two-level tree in a few.

Splitting each line at the first `=` — what most quick converters do — gets a simple file right and a real one wrong. An inline comment ends up inside the value, a quoted string loses its spaces, and a duplicate key disappears without a word.

## Which Rules Does the Converter Follow?

It implements the common ground that php.ini, git-style configs, Windows `.cfg` files and Python configparser actually agree on.

| Rule | Behaviour |
|---|---|
| Section headers | `[section]` opens a block; the name is kept literally |
| Separators | `key = value` and `key: value`, whichever comes first |
| Comments | `;` or `#` at the start of a line, or following whitespace |
| Inline comments | Stripped from unquoted values, kept inside quotes |
| Quoted values | Surrounding quotes removed; everything after the closing quote is a comment |
| Duplicate keys | Last value wins, and every occurrence is reported |
| Root keys | Keys above the first header stay on the JSON root |

Deliberately unsupported, because the dialects disagree: backslash continuations, `%(interpolation)s`, and reading repeated keys as an array.

## How Do Sections Become JSON?

Each `[section]` becomes a nested object, and any keys above the first header sit on the root beside those objects.

This input:

```ini
; php.ini excerpt
engine = On
memory_limit = 256M

[Session]
session.save_handler = files

[Date]
date.timezone = Europe/Istanbul
```

becomes:

```json
{
  "engine": "On",
  "memory_limit": "256M",
  "Session": { "session.save_handler": "files" },
  "Date": { "date.timezone": "Europe/Istanbul" }
}
```

Note that `session.save_handler` stays one key. A dot inside a *key* is just a character; it is not expanded into a tree. The same applies to a dotted *header* such as `[database.primary]`, which becomes one object named `database.primary`. Keeping it literal is what makes a round trip return the file you started with.

## Why Are Numbers Quoted in the Output?

Because an INI reader hands your program text. `port = 8080` is the string `"8080"` to the code that reads it, and pretending otherwise would misrepresent the file.

Turn on **Numbers and booleans** when the consumer expects real JSON types. It promotes clean integers, decimals, `true` and `false`. Two things stay strings on purpose:

- **Values with leading zeros.** `007` is an id, and `7` is a different value.
- **`On`, `Off`, `Yes`, `No`.** Every dialect reads these differently, so they are left as written.

## What Happens to Comments and Duplicate Keys?

Comments are dropped, and they cannot come back. JSON has no comment syntax, so a round trip through JSON loses them. Keep the original file if its comments carry meaning.

Duplicate keys keep the last value, matching what most readers do, and every duplicate is listed under Warnings with the lines it appeared on:

```ini
[server]
port = 8080
port = 9090
```

The JSON holds `"port": "9090"`, and the warning names lines 2 and 3. Nothing disappears silently — which is the point, because a duplicate key in a config is usually a mistake someone needs to see.

## Which JSON Cannot Be Written Back as INI?

Two shapes are refused with a message naming the key, rather than written in a syntax only some parsers accept.

- **A value nested two levels deep.** INI has one level of sections. `{"a":{"b":{"c":1}}}` has nowhere to go.
- **An array.** There is no array syntax every INI parser agrees on. Repeated keys, comma-separated values and `key[]` are all used by someone.

Refusing is the honest answer. A converter that invented `key[0] = ...` would produce a file that loads fine in one program and silently loses data in another.

Values that need protecting are quoted on the way out. A value with leading or trailing spaces, or containing a `;` or `#`, is written in double quotes so it survives a re-read.

## Is Anything Uploaded?

No. Parsing and writing happen in your browser, and no request carries the config text. That matters here more than for most converters, because the files people need to convert — `php.ini`, a database config, a `.conf` with connection details — routinely hold hostnames and passwords.

The page itself is not request-free: like the rest of the site it loads analytics and advertising scripts. Your file is not part of that traffic.

## Common Mistakes

### Mistake 1: Expecting a Dotted Header to Nest

`[database.primary]` becomes one object named `database.primary`, not `database` containing `primary`. If you want a tree, convert first and reshape the JSON afterwards.

### Mistake 2: Turning On Type Inference for a Config Read as Text

If the program reading the output calls something like `getString`, promoting `8080` to a number changes the type it receives. Leave the toggle off unless a schema asks for real types.

### Mistake 3: Assuming Comments Survive a Round Trip

INI to JSON to INI returns the data, not the documentation. Anything explaining *why* a value is set is gone after the first hop.

### Mistake 4: Pasting a Config With Live Credentials Into an Upload Form

This is the failure mode the tool exists to avoid. Confirm a converter runs locally before pasting anything with a password in it.

### Mistake 5: Ignoring the Warnings Line

Duplicate keys and malformed lines are reported, not fixed. Read them before trusting the JSON as a complete picture of the file.

## Tools Used in This Guide

- **[INI JSON Converter](/developers/ini-json-converter/)** — Convert `.ini`, `.cfg` and `.conf` to nested JSON and back
- **[Properties JSON Converter](/developers/properties-json-converter/)** — The same job for Java `.properties`, which has continuation lines and its own escapes
- **[Env JSON Converter](/developers/env-json-converter/)** — The same job for dotenv files, which have no sections
- **[JSON TOML Converter](/developers/json-toml-converter/)** — For TOML, which looks similar but is specified and typed
- **[JSON Formatter](/developers/json-formatter/)** — Inspect or reformat the JSON after converting

## FAQ

**Q: Is the INI to JSON converter free?**
A: Yes. It is free, needs no signup, and has no usage limits. Conversion happens in your browser.

**Q: Can it read a systemd unit file?**
A: Only loosely. Unit files use `[Section]` headers but allow repeated directives that are meaningful as a list, and this converter keeps the last value. Treat the result as a reading aid, not a faithful representation.

**Q: Does it handle php.ini?**
A: Yes, for the structure. Sections, comments and quoted values are read correctly. It does not evaluate php.ini's special constants such as `E_ALL & ~E_DEPRECATED`, which are carried across as text.

**Q: What is the difference between INI and TOML?**
A: TOML has a specification, typed values, real arrays, dates and nested tables. INI has none of those and no standard. TOML files are not INI files, so use the JSON TOML Converter for `.toml`.

**Q: Is it safe to convert a config with passwords in it?**
A: The conversion is local and the text is never sent anywhere, so nothing leaves your machine. Handle the output with the same care as the input.

**Q: Why did my array get refused?**
A: Because no array syntax is accepted by every INI parser. Flatten the array into separate keys with names you choose, so the result loads the way you intend.

## Next Steps

- Converting a Java config instead? Read the [Properties JSON Converter](/developers/properties-json-converter/).
- Moving a config into a modern format? [JSON TOML Converter](/developers/json-toml-converter/) and [YAML TOML Converter](/developers/yaml-toml-converter/) cover the typed formats.
- Working with environment variables? The [Env JSON Converter](/developers/env-json-converter/) and [Env Linter](/developers/env-linter/) handle dotenv files.
