Convert JSON to CSV

Convert a JSON array of objects into a downloadable CSV file, with nested objects flattened via dot notation. Nothing is ever uploaded.

🌐 Español

Drop your files here (.json)

🔒 Private by design: your files are processed locally in your browser and never uploaded to any server.

Dot notation, and how deep the flattening goes

JSON nests and CSV does not. That single mismatch is the whole difficulty of this conversion, and every tool that does it has to pick a policy for what happens to structure that a grid cannot represent.

The policy here is dot notation, applied recursively. A record like {"user":{"city":"NYC"}} produces a column headed user.city holding NYC. Nesting composes without limit, so {"a":{"b":{"c":1}}} becomes a column called a.b.c, and a profile object four levels deep produces four-segment headings rather than a cell reading [object Object].

One thing that is explicitly not treated as nesting is null. JavaScript famously reports null as an object type, and a converter that recursed into it would crash or emit nonsense, so it is handled as an ordinary scalar value and lands in its cell as an empty string.

The cost of the dot convention is ambiguity in one direction. Once a heading reads user.city, there is no way to know whether the source had a nested object or a top-level key with a dot in its name. That rarely matters for a report, and it matters a lot if you plan to convert the result back.

An array value stays in a single cell

The other shape a grid cannot hold is a list. Faced with "tags":["admin","user"], a converter can either spread it across numbered columns such as tags.0 and tags.1, or keep it whole in one cell. This tool keeps it whole and writes it as its JSON text, so the cell literally contains ["admin","user"].

Spreading was rejected on purpose. If arrays became columns, the width of your entire spreadsheet would be dictated by whichever single row happened to have the longest list, and every other row would carry trailing blanks. One user with fifteen tags would add fifteen columns that 99 percent of the file leaves empty.

Keeping the array intact means the column set depends only on the object keys, which is predictable, and the value is recoverable: running JSON.parse over that cell gives the original array back exactly. The trade is that you cannot filter on a single tag in a spreadsheet without splitting the text yourself first.

The header is a union, not the first row’s keys

Real exports are ragged. An API returns some records with an optional field and some without, a survey has questions that only appear on branching paths, and a database dump has columns added mid-history.

A naive converter reads the keys off the first object and assumes the rest match. When one does not, every value after the missing field shifts one column left, and the damage is invisible until somebody scrolls to row 40 and notices the email addresses are in the phone column.

This converter scans every row before writing anything and builds the header from the union of all keys seen, in the order each one first appeared. Each row is then rendered against that same complete column list, and a key that row does not have becomes an explicit empty cell rather than a gap. Ragged input produces an aligned table.

The order rule has a consequence worth planning around: a field that only exists on your last record becomes the final column. If you want a sensible layout, make sure the first object in the array is a complete one.

Converting a batch of .json files

  1. Drop your .json files into the box above, or click Choose files. Several at once is fine, and more can be added before you start.
  2. Check the list. Each file is converted independently into its own CSV.
  3. Click Convert JSON to CSV. The progress bar advances one step per file.
  4. Download each result. Every CSV keeps its source filename with the extension swapped, so orders.json comes back as orders.csv.

RFC 4180 quoting, CRLF endings and Excel

Quoting is the part that quietly ruins spreadsheets, so it is handled to the letter of RFC 4180. A field is wrapped in double quotes whenever it contains a comma, a double quote, or a carriage return or line feed, and any double quote inside it is doubled. A field with none of those characters is written bare, which keeps the file readable.

Header cells go through the same escaping as data cells, which matters more than it sounds, because a key containing a comma is perfectly legal in JSON and would otherwise split your header row. Lines are joined with CRLF, as the specification requires.

This escaping is used across the site rather than reimplemented per tool: the CSV Viewer, the Fake Data Generator and many other modules import the same function, so a product description full of commas or a multi-line note behaves identically wherever it turns up.

One thing the file does not carry is a byte order mark. That is correct UTF-8, and it is also why Excel on Windows can mangle accented characters when you double-click the file instead of importing it.

Inputs that are not an array of objects

An array of objects is the expected shape, but a few others are accepted rather than refused. A single top-level object, not wrapped in an array, converts to a one-row CSV. An array of plain values such as ["a","b","c"] becomes a single column headed value, and so does any element that is not a plain object, including an array appearing directly at the top level.

An empty array is the one case that stops the run. There is no way to derive a column set from zero rows, and handing you a blank download would look like a broken tool rather than an empty input, so it fails instead. Invalid JSON fails too, and because files are processed in one loop, a single unparseable file aborts the whole batch.

If you are not sure your file is well formed, open it and paste its contents into the JSON Formatter first, since that page works from a textarea rather than a dropzone. Going the other way is CSV to JSON, and if you want a real spreadsheet rather than a text file, JSON to Excel writes .xlsx directly. More of these utilities sit on the developer tools hub.

See it in action

Screenshot of the Convert JSON to CSV tool with sysfenix-sample.json (274 B) loaded
Convert JSON to CSV mid-process: sysfenix-sample.json (274 B) loaded.
Screenshot of the Convert JSON to CSV result screen showing sysfenix-sample.csv ready to download (241 B, 12% smaller)
The finished result: sysfenix-sample.csv ready to download (241 B, 12% smaller). The download link is a local blob URL — the file never leaves your device.

Frequently asked questions

One file in my batch was broken and I got nothing at all. Is that right?

Yes, that is how it behaves. Files are converted one after another in a single run, so a parse failure part way through aborts the whole batch rather than returning the files that already succeeded. Drop the good files on their own, or fix the broken one, and run again.

How do I tell an explicit null apart from a missing key in the output?

You cannot, and that is deliberate. CSV has no null type, so a key holding JSON null and a key that simply is not present in that object both render as an empty cell. If the distinction matters for your data, write a sentinel value such as the text "null" into the JSON before converting.

My accented characters look wrong when I double-click the CSV in Excel.

The file is written as plain UTF-8 with no byte order mark, which is correct and which every other tool reads properly. Excel on Windows guesses the encoding when you open a CSV directly and often guesses the legacy code page instead. Use Data then From Text/CSV and pick UTF-8, or open it in Google Sheets, which gets it right without being told.

What if one of my keys already contains a dot?

It becomes ambiguous. A top-level key literally named user.city produces exactly the same column heading as a nested city inside a user object, and nothing in the CSV records which one it was. Rename the offending keys in the source data if you need the round trip back to JSON to be exact.

Do very large ID numbers survive intact?

Not necessarily, and the loss happens before the CSV is written. The file is handed to JSON.parse first, which turns every number into a double-precision float, so an identifier beyond about sixteen digits is rounded at that point. Export those fields as JSON strings rather than numbers if precision matters.

Does the column order follow my JSON or get sorted?

It follows your data, never alphabetically. Keys appear in the order they are first encountered while scanning the rows top to bottom, so a field that only exists on the last record ends up as the rightmost column. Putting a complete, representative object first gives you the column order you probably wanted.

Related tools