JSON Flatten & Unflatten

Nested JSON Input
1
Delimiter
Flat JSON Output

Last updated:

Jsonic's JSON Flatten tool converts a nested JSON object into a flat key-value map using dot notation by default. A nested path like {"user":{"address":{"city":"Paris"}}} becomes {"user.address.city":"Paris"}. Arrays are indexed numerically: items[0].name becomes "items.0.name". The Unflatten mode reverses the process, reconstructing a nested object from a flat map. You can customize the key delimiter — use "/" for path-style keys or "_" to produce identifiers. All processing runs in your browser with no data upload.

What dot-notation flattening produces

Flattening walks every key of a nested object and replaces each intermediate object with a segment of a dotted path. The output is one flat map of path → leaf value, with no remaining nesting. A three-level object collapses to keys like a.b.c.

{
  "user": {
    "name": "Alice",
    "address": { "city": "Paris", "country": "FR" }
  },
  "active": true
}
{
  "user.name": "Alice",
  "user.address.city": "Paris",
  "user.address.country": "FR",
  "active": true
}

How arrays get indexed

Arrays do not have named keys, so each element is addressed by its position. A list of objects like items expands to items.0.name, items.1.name, and a list of primitives expands to tags.0, tags.1. This turns every leaf into a scalar — exactly what a CSV column or key-value store needs.

{
  "items": [
    { "name": "Widget", "qty": 2 },
    { "name": "Gadget", "qty": 1 }
  ],
  "tags": ["new", "sale"]
}
{
  "items.0.name": "Widget",
  "items.0.qty": 2,
  "items.1.name": "Gadget",
  "items.1.qty": 1,
  "tags.0": "new",
  "tags.1": "sale"
}

Unflatten: rebuild nested JSON from dotted keys

Unflatten is the inverse. It splits each key on the delimiter and recreates intermediate objects — and crucially, when a path segment is a number it rebuilds an array rather than an object with keys "0" and "1". So a round-trip restores the original shape.

// flat input
{
  "user.name": "Alice",
  "items.0.name": "Widget",
  "items.1.name": "Gadget"
}

// unflattened output
{
  "user": { "name": "Alice" },
  "items": [ { "name": "Widget" }, { "name": "Gadget" } ]
}

Choosing a delimiter

The dot is the default because it mirrors JavaScript property access, but it is a poor fit when keys feed into systems where dots are illegal. Switch the delimiter for the destination:/ for URL-style paths, __ (double underscore) for environment variables. The one rule: never pick a delimiter that already appears inside a key name, or unflatten can no longer tell where one path segment stops.

// delimiter "__" for env-var generation
{ "database": { "host": "localhost", "port": 5432 } }

// →
{ "database__host": "localhost", "database__port": 5432 }

// then: DATABASE__HOST=localhost  DATABASE__PORT=5432

Empty objects and empty arrays

These are the round-trip trap. An empty object or array contains no leaf, so a strict flatten emits no key for it and the branch silently vanishes — flatten then unflatten will not return an identical document. If you need empty containers preserved, use a library option that keeps them, or store the original alongside the flat form.

{ "user": { "name": "Alice" }, "meta": {}, "tags": [] }

// strict flatten — empty branches drop out
{ "user.name": "Alice" }

// unflatten can no longer recreate "meta" or "tags"

Flatten JSON in code

When you need this in a script instead of the browser tool, three common options:

// JavaScript — pure recursive flatten (arrays indexed)
function flatten(obj, prefix = "", out = {}) {
  for (const [k, v] of Object.entries(obj)) {
    const key = prefix ? prefix + "." + k : k
    if (v !== null && typeof v === "object") flatten(v, key, out)
    else out[key] = v
  }
  return out
}
// Node.js — the flat npm package (handles edge cases)
import { flatten, unflatten } from "flat"
flatten({ a: { b: 1 }, tags: ["x"] })   // { "a.b": 1, "tags.0": "x" }
flatten(obj, { safe: true })             // preserve arrays as leaves
flatten(obj, { delimiter: "__" })        // custom delimiter
# Python — pandas json_normalize for analysis pipelines
import pandas as pd
flat = pd.json_normalize(data, sep=".").to_dict(orient="records")[0]
# or expand arrays of objects into rows:
pd.json_normalize(orders, record_path=["items"], meta=["id"], sep=".")

Where flattening is used — and next steps

  • CSV / spreadsheet export — scalar cells require a flat row.
  • Relational columns and key-value stores that reject nested types.
  • Config-to-environment-variable generation with a __ delimiter.
  • Key-level diffing of two JSON documents.

For full implementations — the flat npm package, Python flatten_dict, pandas json_normalize(), circular-reference detection, and more array strategies — read the Flatten Nested JSON guide. If your end goal is a spreadsheet, flatten first then use JSON to CSV.

How to flatten or unflatten JSON

  1. Select mode: Flatten (nested → flat) or Unflatten (flat → nested).
  2. Paste your JSON into the left panel, or click Example.
  3. Optionally change the delimiter (default: ".").
  4. Click Flatten or Unflatten.
  5. Copy the result from the right panel.

FAQ

What does JSON flattening do?

Flattening converts a deeply nested JSON object into a single-level map where each key is the full path to a leaf value. For example, {"a":{"b":1}} becomes {"a.b":1}. It is useful for databases that do not support nested types, dot-notation config keys, and tools that only handle flat key-value pairs.

What is the difference between flatten and unflatten?

Flatten converts nested JSON → flat dot-notation map. Unflatten is the inverse: it takes a flat map and reconstructs the nested object, including rebuilding arrays from numeric index segments. You can round-trip: flatten, edit the flat keys, then unflatten.

How are arrays handled when flattening?

Array elements are indexed numerically. ["a","b"] at key "tags" becomes "tags.0":"a" and "tags.1":"b"; items[0].name becomes "items.0.name". When unflattening, keys with numeric path segments are reconstructed as arrays.

Can I use a custom delimiter?

Yes. The default is ".". Use "/" for URL-style paths, "__" for environment variable names, or any string. Use the same delimiter for both flatten and unflatten, and never pick one that appears inside a key name.

How are empty objects and arrays handled?

Empty {} and [] have no leaf values, so a strict flatten emits no key and the branch disappears — meaning the round-trip is not lossless for empty containers. Preserve the originals or use a library option that retains empty objects.

Can it flatten an array at the top level?

Yes. If the root is an array, each element is indexed by position: [{"id":1},{"id":2}] becomes {"0.id":1,"1.id":2}. Unflatten turns numeric root segments back into an array.

Is there a size limit?

No hard limit. It runs in your browser and can handle large files within available memory. For files over ~10 MB, the jq command-line tool or Python pandas is faster.