How to flatten JSON
Flattening turns a nested document into a single level of path keys. It is the right answer for key-value stores and spreadsheets, and the wrong one surprisingly often.
Last reviewed
What flattening actually does
A flattened document has no nesting. Every leaf value from the original sits at the top level under a key that spells out the route taken to reach it, so a value that was inside two objects ends up under a key naming both of them.
Array elements are handled the same way, with the index becoming a path segment. Nothing is discarded, which is what makes the operation reversible in most cases.
{
"orderId": "SO-2026-0417",
"customer": { "id": 7714, "email": "[email protected]" },
"lines": [{ "sku": "TENT-2P", "quantity": 3 }]
}{
"orderId": "SO-2026-0417",
"customer.id": 7714,
"customer.email": "[email protected]",
"lines.0.sku": "TENT-2P",
"lines.0.quantity": 3
}When it is the right move
Flattening is worth doing when the destination genuinely cannot hold nesting. That is a narrower set of cases than it first appears, and applying it anywhere else usually makes the data harder to work with rather than easier.
- Key-value stores — Redis, etcd, Consul and most feature-flag services take one level of keys.
- Environment variables, where a convention such as DATABASE__HOST is already a flattened path.
- Spreadsheet and CSV export, where every column has to be a single scalar.
- Diffing two documents, because a flat map makes a changed leaf a one-line difference instead of a nested block.
- Translation catalogues, which are conventionally stored as dotted keys.
Three notations, and why the choice matters
The path separator is a convention rather than a standard, and the one you pick determines whether the result can be reversed. Dotted notation is the most common and reads best. Bracketed notation distinguishes array indices from object keys, which removes one whole class of ambiguity. Underscore notation exists mainly because environment variables cannot contain dots.
The risk in every case is a key that already contains the separator character. A document with a key literally named "user.name" produces exactly the same path as a nested user object with a name field, and no amount of care at unflattening time can tell the two apart.
- Dotted — customer.contact.email, and lines.0.sku for arrays. Readable, ambiguous for keys containing dots.
- Bracketed — customer.contact.email, and lines[0].sku for arrays. Array indices become unmistakable.
- Underscore — customer_contact_email. Required by some tooling, and the most collision-prone of the three.
Two things flattening loses
The first is the distinction between an object key that is a number and an array index. When unflattening reads a segment made only of digits it has to decide, and treating it as an index is the only choice that reverses ordinary arrays correctly. The cost is that an object whose keys were "0" and "1" comes back as an array.
The second is type information, but only if you use the wrong tool. Flattening for CSV converts every value to text because a spreadsheet cell is text. Flattening for a JSON-consuming system should not — a number that arrives back as the string "3" will fail validation downstream. Convert2JSON keeps types in the JSON Flattener and stringifies only in the CSV converters, because those are genuinely different jobs.
Flattening is not querying
A common reason people reach for flattening is to find a value inside a large document. That works, but it is the long way round: flattening the whole document to locate one leaf does far more work than asking for the leaf directly.
If the goal is to extract or filter, a query language is the better tool. JSONPath and JMESPath both address nested data directly and return only what you asked for, leaving the document alone.
Keep reading
- What is JSON? — JSON is a text format for structured data. It has six value types, one page of grammar, and a handful of rules that trip people up constantly.
- JSONPath examples — One sample document, and the expressions people actually need against it, each with the result it produces.
- JSON vs CSV — CSV holds rows of text. JSON holds a typed tree. Every conversion between them either flattens something or invents something.