Developers

How to Convert JSON to CSV (Without Losing Data)

6 min read

Converting JSON to CSV means turning an array of objects into a header row plus one data row per object: the keys become column names, the values become cells. The part that trips people up isn’t the shape, it’s escaping. Any cell containing a comma, a quote, or a line break has to be wrapped in quotes, or the CSV silently breaks into the wrong number of columns the moment someone opens it in a spreadsheet.

Why CSV still matters

JSON is what APIs and JavaScript speak natively. CSV is what everything else expects: Excel, Google Sheets, a client’s accounting software, a data pipeline that only ingests flat files, a COPY command into a SQL table. When an API response needs to land in front of a non-technical person, or feed a tool that has never heard of nested objects, CSV is the format that just opens and works. The tradeoff is that CSV can only represent flat, tabular data, rows and columns, nothing nested. Getting from JSON’s tree structure to that flat table is where the actual conversion logic lives.

A worked example: three rows, three edge cases

Here’s a small product export as JSON:

[
  { "sku": "A100", "product": "Wireless Mouse, Black", "price": 19.99, "in_stock": true },
  { "sku": "A101", "product": "17\" Laptop Stand", "price": 42.5, "in_stock": false },
  { "sku": "A102", "product": "USB-C Cable", "price": 8.99, "in_stock": true }
]

Run through the converter, it becomes:

sku,product,price,in_stock
A100,"Wireless Mouse, Black",19.99,true
A101,"17"" Laptop Stand",42.5,false
A102,USB-C Cable,8.99,true

The header row comes from the union of keys across every object, in the order each key first appears: sku, product, price, in_stock. That distinction matters more than it looks. A naive converter that only reads the first object’s keys will happily drop a column if a later row introduces a field the first row didn’t have. This tool scans all rows before it writes the header, so nothing gets dropped.

Now the three rows, one edge case each:

Row 1’s product value is Wireless Mouse, Black. That comma would normally read as a column boundary, so the whole value gets wrapped in double quotes: "Wireless Mouse, Black". Once it’s inside quotes, the comma is just a character in the cell, not a delimiter.

Row 2’s product value is 17" Laptop Stand, an inch mark right after “17”. A literal double quote inside a quoted CSV field has to be doubled, so " becomes "", and the whole value still gets wrapped in an outer pair of quotes on top of that: "17"" Laptop Stand". This is the RFC 4180 escaping rule, and it’s the one people get wrong when they hand-build a CSV string with .join(',') and no escaping step at all.

Row 3’s USB-C Cable has no comma, no quote, no line break, so it passes through unquoted. Same for the price numbers and in_stock booleans across all three rows: none of them contain a trigger character, so none of them get quoted.

Missing keys become empty cells, not errors

Real-world JSON is rarely uniform. Say a second export has one object missing a field that a later object introduces:

[
  { "sku": "A200", "product": "Desk Mat", "price": 14 },
  { "sku": "A201", "product": "Keyboard", "price": 55, "color": "gray" }
]

The header row picks up color because it appears somewhere in the array, and the first row simply gets an empty cell for it:

sku,product,price,color
A200,Desk Mat,14,
A201,Keyboard,55,gray

No object needs every key. A missing key just leaves that cell blank instead of throwing an error or shifting every later column out of alignment.

Convert your own JSON

Paste an array of objects below and the CSV updates as you type, entirely in your browser. Nothing you paste is sent to a server.

CSV → JSON JSON → CSV
JSON to CSV Converter
Free, no sign-up, works on any device.
Open the full tool

Common mistakes and edge cases

Nested objects turn into [object Object]. If a value is itself an object, like "address": { "city": "Austin", "zip": "78701" }, converting it directly produces the literal text [object Object] in that cell, not the underlying data. This is real data loss, not a display quirk. The fix is to flatten nested objects into top-level keys before converting: turn address: { city, zip } into address_city and address_zip as separate flat fields on the same object.

Arrays get flattened to a comma string, not separate columns. A value like "tags": ["red", "blue"] doesn’t become two columns or a bracketed string. It gets joined with commas into red,blue, and because that string now contains a comma, the escaping rule correctly wraps it in quotes: "red,blue". That’s useful once you know it (one cell holds a readable, comma-joined list) but surprising if you expected the brackets to survive or expected each array element to land in its own column.

A single object instead of an array. The converter expects an array of objects, [{...}, {...}], even if you only have one row. Passing a bare object, {"sku": "A100", ...} without the surrounding [ ], isn’t valid input. Wrap it in brackets first: [{"sku": "A100", ...}].

Comma-delimited CSV opening wrong in some European Excel installs. This isn’t a bug in the conversion, it’s a regional settings mismatch. Excel installs in locales where the comma is the decimal separator (French, German, Spanish, Italian, and others) expect a semicolon as the CSV list separator by default. Open a comma-delimited CSV in one of those and every column can dump into cell A as one long string. The fix on the Excel side is “Data > Text to Columns,” choosing comma as the delimiter, or changing the OS regional list separator setting. The CSV file itself is valid; Excel is just guessing the wrong delimiter for that locale.

Frequently asked questions

What input structure does the tool expect? A JSON array of flat objects, [{...}, {...}]. Each object represents one row. If the JSON isn’t valid, or isn’t an array of objects, the tool shows an inline error instead of producing broken output.

Are nested objects supported? Not automatically. A nested object value gets stringified to the literal text [object Object], which loses the underlying data. Flatten nested fields into top-level keys, like address_city and address_zip instead of a nested address object, before converting.

Does the column order follow the order of keys in my JSON? Yes. Columns appear in the order each key first appears while scanning the array, not alphabetically and not by count. If your second object introduces a key the first object doesn’t have, that key still gets a column, added at the point it first shows up.

Is my data uploaded anywhere? No. The conversion runs entirely in your browser. Nothing you paste, and nothing in the CSV it produces, is sent to a server.

Can I convert CSV back to JSON? Yes, use the companion CSV to JSON tool for the reverse direction. It parses a CSV’s header row into object keys and each following row into one object.

JSON to CSV Converter
Now try it yourself with the full tool.
Try it now
Related tools