Flatten nested JSON to CSV
Paste or drop a JSON object or array. Get a flat CSV table with dotted column names. Runs in this tab. Your inputs stay in this browser.
.json file here, or choose one. Max 1 MB.Input
One JSON document: an object or an array. Up to 1,048,576 bytes (1 MB). Paste it, or drop a file. UTF-8.
Output
Copy CSV and Download .csv give RFC 4180 CSV with a header row. Every row ends with CRLF, the last one too. A root object gives one row. Nested objects become dotted column names (user.id). An object under a key is flattened as soon as that key is reached, before the next key. An empty key at the top level adds no part to the names of the keys in the object under it, so {"":{"a":1}} gives a. In numbered columns under it the name starts with a dot (.0.a).
- A root array gives one row per element. An object element is flattened into columns. A plain value, or an array written as compact JSON text, goes in a column named
value, the same column as any key namedvalue. Compact JSON text is what JavaScript'sJSON.stringifywrites, with no spaces added. - Inside a row, an array of plain values is joined with
|in one column, and a|inside a value is not escaped. Any other array becomes numbered columns: an object in it is flattened under its number (items.0.sku), and a plain value or an array sits in the numbered column itself, an array as compact JSON text with any objects in it. - The header is every key found, sorted one dotted part at a time, each name split at every dot, a dot inside a key too: parts of digits only in numeric order, other parts by character code, so capitals come first. A part of digits too large for JavaScript to hold as a number, worth about 1.8e308 or more, counts as a text part. Where number and text parts meet at the same place, or number parts are too long for JavaScript to tell apart (past about 15 digits) or equal as numbers like 07 and 7, the order can follow the input.
- Missing values, null and empty text are empty cells, and so is an empty object or array under a key. In a numbered column, an empty array is written as
[]and an empty object adds no column. - true and false are written as they are. Numbers are written as JavaScript reads them, so 1.0 becomes 1, 1e2 becomes 100, and very long numbers lose digits. A number too large for JavaScript, such as 1e400, is written as null, or as Infinity inside a
|joined list. - If a key repeats in one object, the last value wins. If a key with a dot in it, or a key under an empty top-level key, matches another name in the same row, the one reached later gets
#2, or the next free number in that row, added at the very end of its whole name, so every value is kept. In each object, keys that are whole numbers from 0 to 4294967294, written without leading zeros, are reached first, smallest first; then the other keys, in the order each first appears. Across rows, the same name is the same column. - A cell that starts with
=,+,-,@, a tab, a carriage return or a byte order mark gets a leading apostrophe (') so a spreadsheet shows it as text instead of running it. A plain number is left as it is: an optional + or -, then digits with at most one decimal point and at least one digit in all, then an optional exponent: e or E, an optional sign and at least one digit, such as -5, +1.5e3 or -.5. A cell that starts with a byte order mark gets the apostrophe before it, even when a plain number follows. A cell that holds a comma, a double quote, a semicolon, a tab or a line break is quoted, and the apostrophe goes inside the quotes. A line break inside a quoted cell is kept as written. Column names get the same. The rule reads the text of each cell, so the text "-5" is left as it is, like the number -5, and-5|3gets the apostrophe. The apostrophe and the quotes guard the file when it is read with commas between cells. When a spreadsheet splits on semicolons or tabs instead, they do not: a semicolon, a tab or a line break inside a value or a column name, or a number that starts with + or - in the first column, can start a cell that the spreadsheet may run as a formula.
Limits
- One document per run. No merging across files.
- Nesting up to 64 levels. The outermost object or array is level 1, and every object or array inside it adds a level, arrays the same as objects, empty ones too.
- Up to 60,000 objects and arrays in all, the outermost one included.
- Up to 20,000 different keys in all, at every level, counted by their text as written between the quotes. A key written two ways, such as
aand\u0061, counts as two. - Up to 50,000 rows and up to 10,000 columns.
- Up to 250,000 cells, counted as data rows times columns, the header row not included, empty cells included.
- Up to 1,048,576 bytes (1 MB) of column names in all, counted in UTF-8 over each whole name, dots, number parts and any
#2included, before any apostrophe or quotes are added. A long key repeats in the name of every column under it. - Nesting, rows, objects and arrays, and keys are counted in the text before it is read as JSON. There, rows are the commas at the top level of a root array, plus one, and a key is a text in quotes followed by a colon, spaces allowed between. Brackets, commas and colons inside a text in quotes are not counted, and an escaped quote (
\") does not end it. A text past one of these is stopped for that limit, even if it is not valid JSON. - Each limit is inclusive: a text at the limit is allowed, one past it is stopped. Past any of these limits the tool stops and says so. When a text is past more than one, the note names one: nesting first, then rows, objects and arrays, and keys. After reading, columns, cells and column name bytes are checked in that order each time a new column is found, and the first one past stops the run.
- No schema inference, no account, no settings.
Inputs not stored
The flattening runs in your browser tab. This page makes no network request with your inputs. They are not uploaded or stored. The tool sets no cookie, uses no local storage and sends no analytics about your inputs.
Errors
Every error names the field, the rule, and shows a small valid example. There is no support desk. If the box does not explain it, the input is outside what this tool does.