JSON to CSV
JSON to CSV converts an array of records into a spreadsheet-ready grid in your browser. Nested objects and arrays become explicit, reversible column paths rather than being flattened away or dropped, and the column set is the union of every record so fields that appear only in later rows survive.
How does JSON to CSV work?
The hard part of this conversion is not the syntax, it is the shape mismatch. CSV is a rectangle: a fixed set of columns, one row per record, one scalar per cell. JSON is a tree. Every converter has to decide what happens when a record contains {"customer":{"name":"Ada"}}, and most of them decide quietly — by dropping the nested object, by pasting [object Object] into the cell, or by serialising the whole subtree back to JSON inside a single field.
The decision here is an explicit path encoding. customer.name for an object member and tags[0] for an array index. The two notations are deliberately different so the mapping is reversible: with dots alone, a.0 cannot say whether a is an array or an object with a key called “0”, and a round trip through CSV and back would guess. Paste the result into CSV to JSON and you get the document you started with.
The second decision is the column set. The obvious implementation reads the keys off the first record and uses them as the header — and silently loses every field that only appears later. Real exports are heterogeneous: an optional note on one order in fifty, a discount that only applies sometimes. The column set here is the union across every record, in first-seen order, so nothing is dropped and the ordering still reads naturally.
Arrays get a choice, because there is no right answer. Explode gives each element its own column and round-trips exactly. Join puts them in one cell separated by a delimiter, which is what somebody opening this in a spreadsheet usually wants — and is lossy, so it applies only to arrays of scalars; an array of objects is always exploded, because joining it would destroy it.
Quoting follows RFC 4180: a field is quoted when it contains the delimiter, a double quote, a newline, or leading or trailing whitespace that a spreadsheet would otherwise strip. Quotes inside a quoted field are doubled. Everything else is emitted bare, because a file where every cell is quoted is harder to read and no more correct.
JSON in
[
{ "id": 1, "user": { "name": "Ada" }, "tags": ["a","b"] },
{ "id": 2, "user": { "name": "Grace" }, "tags": ["c"], "vip": true }
]CSV out
id,user.name,tags[0],tags[1],vip 1,Ada,a,b, 2,Grace,c,,true
How do nested JSON objects become spreadsheet columns?
The customer object has no column of its own; its keys become dotted column paths, so a spreadsheet gets one flat row per record.
JSON records
[
{ "id": 1, "customer": { "name": "Ada", "city": "London" }, "total": 42.5 },
{ "id": 2, "customer": { "name": "Grace", "city": "New York" }, "total": 7 }
]CSV
id,customer.name,customer.city,total 1,Ada,London,42.5 2,Grace,New York,7
Columns are the union of every record's keys, in first-seen order, so a field that only some records carry still gets a column and an empty cell elsewhere.
What options and edge cases does JSON to CSV support?
| Parameter | Type | Default | Behaviour & edge cases |
|---|---|---|---|
| Delimiter | , ; tab | | , | Semicolon is the de-facto standard in locales where the comma is the decimal separator, and is what Excel expects there. Tab avoids quoting almost entirely, since tabs are rare inside data. |
| Array mode | explode | join | explode | Explode gives tags[0], tags[1] and round-trips exactly. Join collapses scalars into one cell and is lossy. An array of objects is always exploded regardless, because joining it would lose the structure entirely. |
| Quote all | boolean | false | By default a field is quoted only when RFC 4180 requires it. Some strict importers prefer everything quoted; the output is valid either way. |
| Header row | boolean | true | Emits the flattened column paths as row one. Without it the column meanings are positional only, and a round trip back to JSON cannot reconstruct the nesting. |
| Column set | union | all records | Every column that appears in any record, in first-seen order. Reading the header off record one is the commonest way a converter silently drops data. |
| null | value | empty cell | Written as an empty field rather than the text "null", because a spreadsheet treats the literal word as a string. This means null and absent are indistinguishable in the output — inherent to CSV, not to this tool. |
| Top-level shape | array | object | array | An array of records is the expected input. A single object becomes one row. An object with exactly one array member — the {"data":[…]} envelope most APIs return — uses that array, and says so. |
| Input size | bytes | 8 MB | Conversion runs on the main thread, so above this ceiling it is declined rather than attempted. Nothing is uploaded at any size. |
Frequently asked questions
What happens to nested objects?
They become dotted column names: {"customer":{"name":"Ada"}} produces a column called customer.name. Arrays use bracket notation — tags[0], tags[1] — so the two are distinguishable and the conversion is reversible. That is the difference from most converters, which either drop the nested object, write [object Object] into the cell, or stuff a JSON blob into one field.
My records have different fields. Will some be dropped?
No. The column set is the union of every record's fields, in the order they are first seen, so a note that appears on only one order in fifty still gets its own column with empty cells everywhere else. Converters that read the header off the first record alone lose those fields silently, which is the failure most worth avoiding here.
Can I convert the CSV back to the original JSON?
Yes, with explode mode and the header row on. Paste the result into CSV to JSON and the nesting is rebuilt from the column paths. Two caveats are inherent to CSV rather than to the tool: a cell cannot distinguish the string "22201" from the number 22201, and it cannot distinguish an empty string from an absent field.
Why is my number column quoted in Excel, or showing as a date?
That is Excel's import heuristics, not the file. It aggressively reinterprets anything that resembles a date, and drops leading zeros from anything that resembles a number, which mangles product codes and postcodes. Use Data → From Text/CSV rather than double-clicking the file, and set those columns to Text in the import dialog.
Is my JSON uploaded anywhere?
No. The conversion runs in your browser. Open DevTools, go to the Network panel and paste a document — no request carries it. That matters here more than it might seem: the JSON people convert to CSV is usually an export of real records, which is precisely the data that should not go through an unknown server on its way to a spreadsheet.
Which delimiter should I choose?
Comma unless you have a reason. Semicolon if the file is going to somebody in a locale where the comma is the decimal separator, because that is what their Excel expects — a comma-delimited file opens there as a single column. Tab if the data contains a lot of commas and quotes, since tabs almost never appear inside fields and the file stays readable.