JSON to CSV

Flatten a JSON array of records into a CSV table, with nested objects spread across columns.

Runs on your deviceDeveloperWorkingNo account needed

What this tool does

JSON to CSV parses your input with the browser's JSON parser, finds the list of records inside it, and flattens each record into one flat row. Nested objects become dot-path columns, so a record carrying an address object is written under headings such as address.city and address.zip. The header is the union of every path seen across the whole list, kept in the order those paths first appeared, and a record that lacks one of them leaves that cell empty instead of shifting its values one place left.

Finding the list is the part that catches people out. A top-level array is used as it stands, and an object holding exactly one array property is unwrapped to that array, which covers the usual shape of an API response. An object with no array in it, or with two, cannot be guessed at, so the object itself is written out as a single row. That is what the Path to the list field is for: give it a dot path such as data.items and the guessing is skipped altogether. Numeric segments index into arrays, so data.0.rows resolves, but a key that literally contains a dot cannot be reached this way.

Nested arrays are the other decision. One column per item spreads a two-item tags array across tags.0 and tags.1, which reads well until one record carries a dozen tags and the table gains a dozen columns that are blank for everyone else. Keep as JSON in one column writes the array whole into a single cell instead — less pretty, constant width. Both routes lose most of the type information, because CSV carries none: numbers and booleans arrive as text, and null and an empty object collapse into the same empty cell as an empty string, so nothing reading the file afterwards can tell those apart. An empty array joins them in the indexed mode; the JSON mode writes it out as the two characters [].

The work happens in this browser tab and nothing is uploaded, which matters for the exports people usually paste here — they tend to carry customer names, email addresses and internal identifiers. Three things this converter does not do are worth having in mind first. The input is a text box with no file picker, so a .json file on disk has to be opened and pasted in. The result pane draws the first 200 records as a table rather than the entire list, so a long conversion is best done a slice at a time. And the Delimiter and Write a header row controls shape the CSV the converter assembles internally, while the result pane re-serialises the visible table on its own — so the text you copy out is comma-separated with a header line however those two are set.

How to use it

  1. Paste the JSON. Drop an array of records into the input box, or press Load sample for a short document with nested objects and arrays in it. Parsing is strict, and a trailing comma or a comment is reported with the line and column at which it stopped.
  2. Point at the list, if it is buried. Leave Path to the list empty and the array is located automatically. Fill it in with a dot path such as data.items when the document wraps its rows in several layers, or holds more than one array.
  3. Decide how nested arrays are written. One column per item produces tags.0, tags.1 and so on. Keep as JSON in one column leaves the array intact in a single cell, which holds the column count steady across records of differing lengths.
  4. Know what the delimiter and header controls really reach. Comma, semicolon, tab or pipe are offered, with a header row of column names on by default, and both settings do change the CSV the converter builds: a cell is wrapped in double quotes when it holds a comma, the chosen delimiter, a quote of its own or a line break, and rows are joined with a carriage return and line feed. That CSV is not what you take away, though. The result pane rebuilds its own copy from the table it just drew, so treat the output as comma-separated with a header, and change the separator in a spreadsheet afterwards.

Processing & privacy

Runs on your device. Your file is processed directly in this browser.

Common use cases

Getting an API export into a spreadsheet

A JSON array of orders or users is not something a sheet will open. Flattened into columns first, the same records sort, filter and total like any other table.

Spotting the records that are incomplete

Because the header is the union of every key seen, a field that only some records carry gets a column of its own with gaps in it, and those gaps are usually the thing you were trying to find.

Handing data to someone who does not read JSON

Finance, analysts and clients want rows. A CSV of the same records pastes into a sheet or a document without anyone having to open a code editor.

Reviewing seed or fixture data

Config written as JSON is easier to check as a grid, where every record lines up under the same columns and an odd value stands out from the ones above it.

Questions

Is my JSON uploaded anywhere?
No. The parsing and the flattening both run in this browser tab, so the payload and whatever it carries are not transmitted, logged or stored, and the tool still works with the network disconnected.
How do nested objects become columns?
By dot path, with no depth limit. An address object holding city and zip produces address.city and address.zip, and a value three objects down simply gets a three-part column name.
Why did I get one row instead of my whole list?
Because the list could not be identified. A top-level array is used directly and an object holding exactly one array is unwrapped to it, but an object with no array, or with two of them, is treated as one record. Put the dot path to the array you want into Path to the list.
What happens to records missing a field?
They get an empty cell. Columns are collected across every record in the order they first appear, so a key that only the final record carries still gets a column, and the earlier rows leave it blank rather than sliding their values across.
What exactly does Copy output give me?
A header line plus up to 200 rows, comma-separated, whichever way the Delimiter and Write a header row settings are left. Two things are going on. The table is capped at 200 records because a browser table with fifty thousand rows in it stops being useful, and the copy is re-serialised from that visible table rather than from the CSV the converter produced, so the separator you picked never reaches your clipboard and the line endings arrive as plain line feeds. Convert a long list in slices, and export CSV with a different delimiter from a spreadsheet afterwards.
What happens to null?
It becomes an empty cell, as does an empty object, so the file cannot distinguish either from a genuinely empty string. An empty array depends on the mode: One column per item leaves it empty as well, while Keep as JSON in one column writes [] into the cell. Where that difference matters downstream, keep the structured parts as JSON using the single-column array mode.
Can I turn the CSV back into JSON?
CSV to JSON will read it, but the nesting does not return: a column named address.city comes back as a flat key spelled address.city, not as an object with a city inside it. The flattening is a one-way trip, and numbers and booleans are restored only if you leave that tool's type conversion switched on.
How many records can it handle?
No limit is imposed. Everything is held in the tab's memory, and the flattening pauses briefly every 500 records so the tab keeps answering rather than locking up, though a text tool draws no progress bar while it works. A few megabytes of records is comfortable, and your device rather than a rule here sets the ceiling.

Related tools