JSON to CSV converter
Turn a JSON array of objects into CSV spreadsheet rows. Keys become the header, objects become rows, and quoting follows RFC 4180 so commas inside values survive.
Conversion happens in this browser tab. Nothing is uploaded, logged, or stored.
What converts cleanly and what does not
CSV is a flat grid. JSON is a tree. The conversion only works without loss when your JSON is already grid-shaped: an array of objects where each object is one row and the keys are the columns.
[
{ "sku": "A-1001", "price": 429.00 },
{ "sku": "A-1002", "price": 89.50 }
]
That becomes two rows and two columns. The converter reads every object in the array, collects the union of all keys as the header, and writes one row per object. Objects missing a key get an empty cell rather than a shifted row.
Nested values
When a value is itself an object or an array, there is no cell that can hold it. The
converter serialises it back to JSON inside the cell, which keeps the data but produces
something a spreadsheet cannot filter on. If you need real columns, flatten first —
turn {"address": {"city": "Oslo"}} into a key called
address.city before converting.
Quoting and escaping
Going the other way is CSV to JSON, which reverses this faithfully for grid-shaped data.
Three characters force a cell to be quoted: a comma, a double quote, and a newline. The converter handles all three per RFC 4180.
| Value | Written as |
|---|---|
Monitor arm, dual | "Monitor arm, dual" |
26" display | "26"" display" |
| A value with a line break | Quoted, newline kept inside |
null | Empty cell |
true | true |
Note the doubled quote, not a backslash. CSV escapes a quote by repeating it.
Opening the result in a spreadsheet
Two things regularly go wrong, and neither is the converter's fault.
Leading zeros disappear
Excel and Google Sheets read 00123 as the number 123. SKUs, ZIP codes,
and phone numbers all suffer. Import the file rather than double-clicking it, and set
those columns to Text in the import dialog.
Long numbers become scientific notation
A 16-digit identifier is displayed as 1.23457E+15 and, worse, is
sometimes saved back that way — losing precision permanently. Same fix: import as Text.
Regional separators
In locales that use a comma as the decimal separator, spreadsheets expect a semicolon between fields. If every row lands in one column, that is why.
Doing it in code
# Python, standard library only
import csv, json
rows = json.load(open("data.json"))
cols = list({k: None for r in rows for k in r}) # union, order preserved
with open("data.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=cols)
w.writeheader()
w.writerows(rows)
# jq, for a known set of columns
jq -r '(.[0] | keys_unsorted), (.[] | [.[]]) | @csv' data.json
Personal data does not leave your device
An array of objects flattened into a spreadsheet is, more often than not, a list of people: customers, users, subscribers, employees. That makes this conversion the one most likely to touch personal data covered by the GDPR or comparable law, where sending records to a third party is not a small decision.
You are not making that decision here. The conversion runs entirely in your browser, so no personal data is transferred to us or to anyone else. See the privacy policy for what little we do receive.