This tool converts JSON to CSV in your browser; nothing leaves your machine. For the reverse direction, see CSV to JSON.
The straightforward case
Flat array of objects → CSV with one row per object:
JSON:
[
{"name": "Alice", "age": 30, "city": "NYC"},
{"name": "Bob", "age": 25, "city": "Boston"}
]
CSV:
name,age,city
Alice,30,NYC
Bob,25,Boston
The header is the union of keys; each row is one object. Cells are JSON-escaped for CSV (commas, quotes, newlines are wrapped in double quotes per RFC 4180).
Heterogeneous keys
When objects have different keys, the union is the header:
JSON:
[
{"name": "Alice", "age": 30},
{"name": "Bob", "city": "Boston"}
]
CSV:
name,age,city
Alice,30,
Bob,,Boston
Missing keys produce empty cells. The decision: empty string vs literal null. Most CSV consumers treat empty as null, so emitting empty is the more compatible choice.
Nested objects: flattening
Pure CSV can’t represent nesting. A flattening strategy turns nested objects into dotted keys:
JSON:
[
{
"name": "Alice",
"address": {
"city": "NYC",
"zip": "10001"
}
}
]
CSV (flattened):
name,address.city,address.zip
Alice,NYC,10001
Some tools use _ instead of . (address_city); some use [] syntax for arrays (tags[0]). Pick the convention that matches the consumer.
Arrays of values
A field that’s an array of primitives:
JSON:
{"name": "Alice", "tags": ["vip", "active"]}
CSV options:
A. Joined string: name,tags
Alice,"vip,active"
B. JSON-encoded: name,tags
Alice,"[""vip"",""active""]"
C. Multiple rows: name,tag
Alice,vip
Alice,active
D. Indexed columns: name,tags[0],tags[1]
Alice,vip,active
All four are valid; pick what the consumer expects:
- A is human-readable but ambiguous if a tag contains a comma.
- B is unambiguous but the consumer needs to JSON-decode the cell.
- C denormalizes (one row per array element) — useful for analytics imports.
- D preserves indexability but assumes a known max length.
The tool above uses B: an array or nested object is written into its cell as JSON. It has no option for the other layouts.
Arrays of objects
Most complex case. A field that’s an array of objects:
JSON:
{
"user": "Alice",
"purchases": [
{"item": "Book", "price": 12},
{"item": "Pen", "price": 3}
]
}
Three strategies:
- Flatten with index:
user,purchases[0].item,purchases[0].price,purchases[1].item,purchases[1].price. Hideous for arrays of variable length. - Denormalize to multiple rows: one row per purchase, with the user repeated. Loses 1:1 row-per-object structure.
- JSON-encode the field:
user,purchaseswith the purchases column being a JSON string. Compact but requires the consumer to JSON-decode.
For analytics imports (Looker, Tableau), denormalization is usually the right answer. For round-trippable data interchange, JSON-encoded is best.
Type handling
JSON has typed values; CSV has only strings. The conversion has to decide:
| JSON value | CSV cell |
|---|---|
"string" | string (or "string" if it contains commas/quotes/newlines) |
42 | 42 |
3.14 | 3.14 |
true / false | true / false |
null | empty (or null literal — see below) |
{} (empty object) | empty or {} |
[] (empty array) | empty or [] |
The handling of null is the most variable: empty cell, the literal string null, or NULL are all seen. Most consumers tolerate the empty-cell form; some explicitly distinguish “empty” from “null.”
CSV escaping
When a value contains characters meaningful to CSV, the cell must be quoted and any internal quotes doubled:
| JSON value | CSV cell |
|---|---|
Alice | Alice |
Smith, Alice | "Smith, Alice" |
Said "hi" | "Said ""hi""" |
Line 1\nLine 2 | "Line 1\nLine 2" (literal newline inside quotes) |
The tool above quotes any cell that contains ,, ", \n or \r, which is what RFC 4180 requires. Leading and trailing spaces are kept as they are, unquoted.
Common pitfalls
- Inconsistent keys across rows. Header is the union; cells with no value are empty. Verify after generation.
- Excel auto-formatting. Excel sometimes interprets cells like
12-3as dates or0123as the number 123 (dropping the leading zero). For Excel-bound CSVs, prefix problematic cells with'or use a format Excel won’t reinterpret. - Encoding. UTF-8 is the modern default. Excel on Windows historically expected Windows-1252 — opening a UTF-8 CSV in older Excel versions produces mojibake unless the file has a BOM. Some tools add a UTF-8 BOM to “Excel-compatible” CSV; the tool above doesn’t, so in older Excel use Data → From Text/CSV and pick UTF-8 instead of double-clicking the file.
- Localized number formats. A JSON number
1234.5becomes1234.5in the CSV. Excel in some locales (Germany, France) expects1234,5— opening will misparse. Either align with the consumer’s locale or use TSV with the same approach. - Lost precision. A 64-bit integer in JSON (
12345678901234567890) doesn’t fit in JavaScript’s number type and may lose precision when parsed. The CSV cell may be1.234567890123457e19instead of the original digits. For large integers, the JSON consumer needs a big-integer-aware parser.
For the reverse direction, see CSV to JSON. For other JSON conversions, see JSON to TypeScript, JSON to YAML, JSON to Markdown table.