JSON Flatten / Unflatten
Flatten nested JSON to dot- or bracket-path keys and unflatten it back — big numbers exact, entirely on this device.
Joins path segments. The default is a dot — pick one your keys never contain.
Press ? for shortcuts
Do it offline:$ jq '. as $in | reduce paths(scalars) as $p ({}; .[[$p[]|tostring]|join(".")]=($in|getpath($p)))' file.json
How to use it
- Paste nested JSON to flatten, or a flat path-keyed object to rebuild; a badge reads the paste, preselects a direction, and the Flatten and Unflatten tabs switch it by hand.
- Set the delimiter that joins segments and choose brackets or dots for array elements; changing either re-runs the same paste, and both settings return next visit.
- A key that already holds the delimiter is called out on a chip, because that single path can no longer be split apart the same way in reverse.
- Copy either pane, save the output as a .json file, or Share a link that carries your input alongside the delimiter and notation you picked.
Turn a nested JSON document into a flat object whose keys are the full path to each value — user.name, user.tags[0] — then rebuild the original from those keys. Pick the delimiter that joins the segments and whether array elements read as brackets or dots. Values and key order are copied through byte for byte, so a 19-digit id keeps every digit, and the whole reshape runs on this device.
Examples
{"user":{"name":"Ada","tags":["x","y"]}}{
"user.name": "Ada",
"user.tags[0]": "x",
"user.tags[1]": "y"
}The delimiter joins each object key and [i] marks each array element, so every leaf becomes one path key. Nothing else moves.
{
"user.name": "Ada",
"user.tags[0]": "x",
"user.tags[1]": "y"
}{
"user": {
"name": "Ada",
"tags": [
"x",
"y"
]
}
}Unflatten is the exact inverse: each path key is split back into objects and arrays, restoring the document example one started from.
{"a.b":1,"c":{"d":2}}{
"a.b": 1,
"c.d": 2
}The key "a.b" already contains the delimiter, so its path reads the same as a nested a then b; a chip marks it as not round-trip safe while the flatten still completes.
{"id":9007199254740993}{
"id": 9007199254740993
}9007199254740993 is one past 2^53, so a tool that parsed it into a JavaScript number would hand back 9007199254740992; here the digits are spliced from your source text, untouched.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Brackets round-trip; dot indices carry an ambiguity
Bracket notation writes an array element as a[0], which never reads as an object key, so it rebuilds unchanged. Dot notation writes a.0 instead, and an all-digit segment is then taken as an array index — so an object keyed 0 would come back as an array element. Reach for brackets when a document mixes numeric keys with arrays.
The one lossy case, and how to sidestep it
Flattening joins segments with the delimiter, so a key that already holds that character produces a path indistinguishable from real nesting. The chip names the offending key; switch the delimiter to something the keys never use — a slash, or a double underscore — and the reverse trip lands back on the original.
Unflatten refuses a collision rather than guess
When one path uses a segment as a final value and another uses it as a parent, no single document satisfies both. Instead of dropping one silently, unflatten stops, names the two keys, and anchors the error at the second so you decide.
Empty containers and long numbers ride through
An empty object or array has no members to expand, so it is kept as a leaf and noted, never quietly discarded. Numbers come from your source text rather than a parse, so an integer past 2^53 or a high-precision decimal returns with every digit — the same reason your pasted key order is preserved.
Common errors
Key collision: `a` conflicts with `a.b` — a path segment is used as both a value and a parent.- Two path keys disagree about one segment: one treats a as a final value, the other as a container holding a.b. Rename a path, or drop the pair you did not mean, and unflatten can build a single result.
Unflatten needs a flat JSON object of path→value pairs; got an array.- Unflatten reads the flat form — one object whose keys are paths. An array, string or bare number carries no path keys to expand, so reach for Flatten instead if you meant to reshape a nested value.
Input is larger than the 50 MB limit for this tool. For bigger payloads use the CLI: jq '. as $in | reduce paths(scalars) as $p ({}; .[[$p[]|tostring]|join(".")]=($in|getpath($p)))' file.json- A refusal, not a partial pass: reshaping half a document would emit keys that do not describe the whole. The jq line runs the same dot-path flatten in your shell, uploading nothing.
FAQ
Can I use a delimiter other than a dot?
Yes. The dot is only the default; any string of one to eight characters works, so a slash or a double underscore keeps paths legible when your keys themselves contain dots. The same delimiter splits the keys back apart, so pick one your data never uses.
Why did a key that already contained a dot change meaning after unflatten?
Because the dot doubles as the path separator. A flat key like "a.b" cannot be told apart from a nested a holding b, so the rebuild reads two levels. Flatten warns whenever it emits such a key; a delimiter absent from your keys removes the clash for good.
Does flattening change my numbers or key order?
No. Each value is lifted straight from your source text, so a large integer keeps all of its digits and an exponent keeps its spelling, and keys are emitted in the order they appear rather than sorted. Only the shape of the keys changes.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Flatten or unflatten the current input now, at any size.
- ⌘/Ctrl + S
- Download the result as a .json file, taking over the browser save while focused.
- ⌘/Ctrl + C
- With no selection, copy the whole result; a highlighted span copies only itself.
- ⌘/Ctrl + Shift + C
- Copy the whole result even while part of a pane is selected.
- s
- Swap Flatten and Unflatten — idle in text fields, mid-composition, and while a run cancels.
- t
- Step to the next colour theme, unless a field is focused or an IME is active.
- ? or ⌘/Ctrl + /
- Open the shortcut help dialog, where any browser-shortcut conflicts are listed.
- Esc
- Close the frontmost dialog; the input you pasted is never cleared.