JSON ↔ CSV Converter

Convert an array of objects to a CSV table, or a CSV file back to JSON. Nested objects are flattened to dotted columns and rebuilt on the way back.

Processed locally in your browser
JSON
CSV
CSV appears here.
Waiting for inputRuns as you type

How JSON becomes CSV

CSV is a flat table; JSON is a tree. The conversion works when the JSON is an array of objects: each object becomes a row, and the union of all keys (in first-seen order) becomes the header. Missing keys produce empty cells. A single object is treated as a one-row table, and a wrapper such as {"data": [...]} with exactly one array property is unwrapped automatically.

JSON
[
  {"id": 1, "name": "Ada", "role": {"team": "core"}},
  {"id": 2, "name": "Lin, Wei"}
]
CSV
id,name,role.team
1,Ada,core
2,"Lin, Wei",

Nested objects and arrays are flattened into dotted column names by default: role.team, tags[0], tags[1]. With flattening off, nested values are written as JSON text inside a single cell, which is what some spreadsheet import pipelines expect.

How CSV becomes JSON

The first row is read as the header and each following row becomes an object keyed by those names. Cells are converted to numbers, booleans and null when they are unambiguous (42, 3.5, true, an empty cell); everything else stays a string, so a value like 007 or 1e3 is kept as text. Turn off type inference if every value should be a string.

Headers with dots or brackets (role.team, tags[0]) are rebuilt into nested objects and arrays when the flatten option is on, so a JSON → CSV → JSON round trip restores the original structure.

Quoting rules

The output follows RFC 4180: a field containing the delimiter, a double quote or a line break is wrapped in double quotes, and any double quote inside it is doubled ("say ""hi"""). The parser accepts the same, plus CRLF or LF line endings, a UTF-8 byte order mark, and fields with embedded line breaks inside quotes.

The delimiter is detected automatically from the first lines (comma, semicolon, tab or pipe). European spreadsheets often export with semicolons because the comma is the decimal separator; pick it explicitly if detection guesses wrong.

Common problems

  • Different field counts per row. Usually an unquoted comma inside a value. The status line reports the first mismatching row.
  • Leading zeros lost. Postal codes and IDs like 00123 are kept as strings by the inference rules here, but spreadsheets will strip them on open. Format the column as text in the spreadsheet.
  • Excel and UTF-8. Excel may misread UTF-8 without a BOM. If accented characters look wrong after opening the downloaded file, import it via Data → From Text and choose UTF-8.
  • Deeply nested JSON. Arrays of arrays of objects flatten into very wide tables. Reshape the data first (for example with jq) so that each record is one object.

Converting in code

Python

import csv, json
rows = json.load(open("data.json"))
with open("data.csv", "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=rows[0].keys())
    w.writeheader(); w.writerows(rows)

# CSV -> JSON
with open("data.csv", newline="") as f:
    print(json.dumps(list(csv.DictReader(f)), indent=2))

Command line

jq -r '(.[0] | keys_unsorted) as $k | $k, (.[] | [.[$k[]]]) | @csv' data.json
# CSV -> JSON with Miller
mlr --icsv --ojson cat data.csv
navigateEnter openEsc close