JSON to CSV

Convert an array of JSON objects into RFC 4180 CSV. Flattens nested objects into dotted columns, handles sparse records, and offers comma, semicolon, tab or pipe delimiters plus an Excel BOM.

Flatten records into a spreadsheet. Paste an array of objects and get back CSV with a header row. Nested objects become dotted column names, missing fields become empty cells, and values containing the delimiter are quoted according to RFC 4180.

Turning a tree into a table

The shape mismatch

JSON is a tree and CSV is a rectangle, so any conversion has to decide what to do with the parts of the tree that do not fit. The one shape that maps cleanly is an array of flat objects: each object becomes a row and each key becomes a column. Everything else needs a rule.

Nested objects are the easy case. {"role": {"team": "core"}} becomes a column named role.team, which keeps the value addressable and is understood by most spreadsheet import wizards. Nested arrays are harder, because expanding them would change the number of rows and silently duplicate the surrounding data. This converter keeps them as JSON text inside a single cell, which loses queryability but never invents records that were not in the source.

Sparse records and column order

Real-world JSON is rarely uniform. One record has a nickname, the next does not; a field appears only after some migration date. A converter that took its columns from the first object alone would silently drop everything else.

The column list here is the union of every key across every record, in first-seen order. Records missing a field get an empty cell rather than being skipped, so the row count always matches the input length. First-seen order is chosen over alphabetical because it preserves the author's intended grouping — id and name stay at the front instead of being scattered.

Quoting, delimiters and Excel

RFC 4180 requires a field to be quoted if it contains the delimiter, a double quote, or a line break, and an embedded quote is escaped by doubling it. This tool applies that rule to every cell, including the header, so a value like Grace, Jr. or a multi-line address survives a round trip through any conforming parser.

The delimiter choice matters more than it looks. In locales where the comma is the decimal separator — much of continental Europe — Excel expects a semicolon and will otherwise drop the whole row into column A. The BOM option prepends a UTF-8 byte order mark, which is what tells Excel on Windows to read the file as UTF-8 instead of the legacy code page; without it, non-ASCII names arrive mangled. Both options are off the default path precisely because they break other tools, so turn them on only for Excel.

Open-source note: implemented in vanilla JavaScript with no third-party libraries.

FAQ

What input shape does it expect?
An array of objects, where each object is one row. A single object is accepted and produces one row, but an array of strings or numbers cannot become a table.
How are nested objects handled?
They are flattened into dotted column names, so {"role": {"team": "core"}} becomes a column called role.team. Turn flattening off to keep them as JSON text instead.
Why are nested arrays left as JSON?
Expanding them would change the row count and duplicate the surrounding fields. Keeping them in one cell means the output always has exactly as many rows as the input had records.
What happens when records have different keys?
The header is the union of all keys across all records, in first-seen order, and any record missing a field gets an empty cell. No record is skipped.
When should I use the BOM option?
Only for Excel on Windows. The byte order mark tells it to read the file as UTF-8; without it non-ASCII characters are misread. Other tools may show the BOM as stray characters.
Why is my file opening in one column in Excel?
Excel follows your locale's list separator. In locales that use a comma as the decimal mark it expects a semicolon, so switch the delimiter to semicolon and reopen.