What flattening does
Flattening walks every branch of a JSON document and writes each leaf value under the path that leads to it. {"user": {"name": "Ada", "roles": ["admin"]}} becomes {"user.name": "Ada", "user.roles.0": "admin"}: one level deep, with nothing lost.
That shape is what many systems want. Elasticsearch and OpenSearch mappings, i18n translation files, feature-flag services, Redis hashes, environment-style configuration and analytics events all prefer flat keys. A flat object is also easy to diff line by line, to sort, and to paste into a spreadsheet as two columns. When you need one row per array item instead of one object, JSON to CSV is the better fit.
Options
- Delimiter joins the path segments: a dot (
a.b), a slash (a/b, handy next to JSON Pointer), an underscore (a_b) or a custom string such as::or->. Backslashes, digits and square brackets cannot be part of a delimiter, because the path syntax uses them. - Arrays chooses how positions are written. Index segments treat a position like any other segment (
orders.0.total), which is what most libraries such as the npmflatpackage produce. Brackets writeorders[0].total, the style lodash and JavaScript use, which keeps array positions visibly different from object keys.
Indent and Sort keys from the toolbar apply to the output as usual.
Keys that contain the delimiter
A key such as "v1.2" or "https://example.com" would be ambiguous if written as-is: config.v1.2 could mean three levels or two. The tool escapes instead of guessing. Each character of the delimiter inside a key gets a backslash, backslashes in keys are doubled, and with bracket style [ and ] are escaped too. So {"config": {"v1.2": true}} flattens to the key config.v1\.2, which JSON spells "config.v1\\.2".
One more case needs care. With index segments, an object whose keys happen to be exactly "0", "1", "2" would read back as an array, so those keys are written as \0, \1, \2. Objects keyed by IDs such as "1001" are not affected.
Built to round-trip
Empty objects and empty arrays stay in the output as {} and [] values, so their keys do not silently disappear. Numbers keep their exact spelling: 12345678901234567890 and 1.50 are copied character for character rather than passing through a JavaScript double.
Because of the escaping, unflattening the result with the same options gives back exactly the original document. The test suite checks that on thousands of random documents for every delimiter and array style. The only exceptions are an empty top-level array, which has no paths and becomes {}, and, in bracket style, an empty-string key at the top level that holds an array.
Errors and limits
The input must be an object or an array; a lone string or number has no paths, and the error points at it. Invalid JSON is reported with the line and column, as in the JSON validator. Very deep documents are walked without recursion, so nesting depth is not a problem, and multi-megabyte files are processed in a background worker so the page stays responsive.
Examples
API response to dot paths
Nested objects and array positions become dot paths; the empty coupons array is kept as [] so nothing goes missing.
{
"id": 7,
"customer": { "name": "Aisha Tan", "address": { "city": "Singapore", "zip": "018956" } },
"items": [
{ "sku": "KB-104", "qty": 1 },
{ "sku": "MS-220", "qty": 2 }
],
"coupons": []
}{
"id": 7,
"customer.name": "Aisha Tan",
"customer.address.city": "Singapore",
"customer.address.zip": "018956",
"items.0.sku": "KB-104",
"items.0.qty": 1,
"items.1.sku": "MS-220",
"items.1.qty": 2,
"coupons": []
}
Bracket style with a slash delimiter
Array positions are written as [0] and [1], and segments are joined with slashes: service/ports[0], service/tls/enabled.
{
"service": { "ports": [8080, 8443], "tls": { "enabled": true } }
}{
"service/ports[0]": 8080,
"service/ports[1]": 8443,
"service/tls/enabled": true
}
Keys that already contain dots
Dots inside key names are escaped with a backslash, so unflattening restores the original keys instead of inventing extra levels.
{
"versions": { "v1.2": "stable", "v2.0-beta": "preview" },
"hosts": { "api.example.com": { "timeout": 30 } }
}{
"versions.v1\\.2": "stable",
"versions.v2\\.0-beta": "preview",
"hosts.api\\.example\\.com.timeout": 30
}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Flattening needs an object or an array at the top level, but the JSON is a string | The whole input is a single value, for example a quoted string, so there are no paths to write. | Wrap the value in an object such as {“value”: “…”}, or paste the document that contains it. |
The custom delimiter is empty | Delimiter is set to Custom but the Custom delimiter box is blank. | Type the separator you want, for example :: or ->. |
The delimiter "[" cannot be used: backslashes, digits and square brackets are reserved for escapes and array indices | The chosen custom delimiter contains a character that the path syntax already uses. | Pick a delimiter made of other characters, such as | or ::. |
Trailing comma before '}'Explained | The input is not strict JSON; a comma follows the last property of an object. | Remove the comma, or convert the file with JSONC to JSON first if it is a config file with comments. |
Frequently asked questions
How do I get the nested JSON back?
Use the JSON Unflatten tool with the same delimiter and array style. Thanks to the escaping, the result is identical to the original apart from the two documented edge cases.
Why does a key in my output contain a backslash?
The original key contained the delimiter (or a backslash or bracket), so it was escaped to keep the path unambiguous. Unflatten removes the backslash again.
Which array style should I pick?
Index segments match the popular flat package and most key-value stores. Brackets match lodash get/set paths and make it obvious which segments are array positions.
Are big numbers and decimals preserved?
Yes. Values are copied with their original spelling, so 64-bit IDs and trailing zeros such as 1.50 are unchanged.