JSON vs CSV

Updated: August 8, 2026

Hierarchical versus tabular. The choice is decided almost entirely by whether your data has nesting — and by who opens the file at the other end.

Two Shapes of Data

CSV describes a grid: rows and columns, every row the same width. JSON describes a tree: values inside values, to any depth. Nearly every difference between them follows from that.

# CSV
id,name,email,city
101,Alice,alice@example.com,Chennai
102,Bob,bob@example.com,Bengaluru
// JSON
[
  { "id": 101, "name": "Alice", "email": "alice@example.com", "city": "Chennai" },
  { "id": 102, "name": "Bob",   "email": "bob@example.com",   "city": "Bengaluru" }
]

For data that genuinely is a table, CSV is the better fit — it is smaller, it opens in Excel, and the header row states the schema once. The moment the data stops being a table, CSV stops working and JSON keeps going.

Head to Head

JSONCSV
StructureHierarchical, any depthFlat grid only
TypesExplicit — string, number, boolean, nullNone — everything is text
Size (raw)Larger — keys repeat per recordSmaller — header written once
Size (gzipped)Close to CSVMarginally smaller
StandardisedYes — RFC 8259, strictlyRFC 4180, widely ignored
StreamingAwkward — needs JSON LinesNatural — one record per line
Opens in a spreadsheetNoYes

File Size, Honestly

CSV's size advantage is real and frequently overstated. JSON repeats every key on every record, so on a wide table with many rows the raw difference is large. But payloads are almost always compressed in transit, and repeated keys are exactly what compression algorithms eliminate best.

The same effect is measured in detail on the minifier page: stripping repetitive characters from a JSON payload cut 41% of raw bytes but only about 11% after gzip. Repeated keys behave the same way. If your concern is bandwidth rather than disk, enabling compression matters far more than choosing CSV.

Where CSV's compactness genuinely wins is bulk analytical storage — millions of rows at rest, where even compressed size and scan cost matter. At that scale, though, a columnar format like Parquet usually beats both.

CSV Has No Types

Every CSV cell is text. What it means is inferred by whatever reads it, and different readers infer differently.

id,code,active,notes
101,00123,true,
102,1e5,false,N/A

Reasonable questions with no answer in the file itself:

  • Is 00123 the string "00123" or the number 123? Excel will strip the leading zeros and destroy the value.
  • Is 1e5 a product code or the number 100000?
  • Is true a boolean or the four-character word?
  • Is the empty notes cell an empty string, or null, or absent?
  • Is N/A a value, or a marker meaning "no value"?

JSON answers all of these in the document: "00123" is unambiguously a string, 100000 unambiguously a number, and null unambiguously distinct from "". This is the same class of problem as YAML's type inference, discussed on the JSON vs YAML page — except that in CSV there is no quoting convention that resolves it, because quotes are already used for something else.

The Standardisation Problem

RFC 4180 defines CSV, and much of the world ignores it. In practice you cannot assume:

  • The delimiter is a comma. Locales that use a comma as the decimal separator often use semicolons instead, so Excel's output varies by the machine that produced it.
  • Line endings are consistent. CRLF, LF, and occasionally CR all appear.
  • The encoding is UTF-8. Latin-1 and Windows-1252 files are common, and a UTF-8 BOM appears often enough to break naive parsers.
  • Quoting is uniform. Some writers quote every field, some only those containing the delimiter, some neither.
  • There is a header row. Nothing in the format says so.

And the hardest case — a field containing the delimiter, a quote, or a newline:

id,name,quote
101,"Smith, Alice","She said ""hello"""
102,"Bob","A note
spanning two lines"

That is valid RFC 4180: fields containing commas are quoted, embedded quotes are doubled, and a quoted field may contain literal newlines — which means you cannot parse CSV by splitting on commas and newlines, however tempting it looks. Use a real CSV library. JSON has exactly one escaping convention, defined precisely, implemented identically everywhere.

Converting Between Them

JSON to CSV works cleanly only when the JSON is a flat array of objects with consistent keys. Nesting has to go somewhere:

// Nested source
{ "id": 101, "address": { "city": "Chennai", "country": "IN" } }
# Option 1 — flatten paths into column names
id,address.city,address.country
101,Chennai,IN

# Option 2 — embed JSON in a cell (defers the problem)
id,address
101,"{""city"":""Chennai"",""country"":""IN""}"

Arrays of varying length are worse: either one column per possible index, or a delimited string inside a cell. Neither round-trips reliably.

CSV to JSON is mechanically easier — every row becomes an object keyed by the header — but you must decide types, since CSV has none. Does "123" become a number? Does an empty cell become "", null, or an omitted key? Answer these deliberately rather than letting a library guess.

# jq: convert a JSON array of flat objects to CSV
jq -r '(.[0] | keys_unsorted), (.[] | [.[]]) | @csv' data.json

Choosing

Use JSON when

  • Data is nested or records vary in shape
  • Types must survive the trip
  • It is an API request or response
  • Null and empty must be distinguishable
  • A schema will validate it

Use CSV when

  • The data is genuinely tabular
  • A human will open it in a spreadsheet
  • It feeds a statistical or BI tool
  • You are bulk-loading a database
  • Streaming row-by-row matters

A common and sensible arrangement is to use JSON throughout the system and offer CSV as an explicit export for users who will open the file in Excel. Make it a separate endpoint or a ?format=csv parameter — never the default response of a JSON API.

Frequently Asked Questions

Which is smaller, JSON or CSV?

CSV, because it writes each column name once in a header row while JSON repeats every key on every record. On tabular data the raw difference is substantial — but after gzip compression it narrows sharply, since repeated keys compress extremely well.

Can CSV represent nested data?

Not natively. CSV is a flat grid, so nesting must be faked — by flattening paths into column names like address.city, or by embedding a JSON string inside a cell. Both work and both are awkward.

Is there a CSV standard?

RFC 4180 exists but is widely ignored, which is the format's central weakness. Delimiters, quoting, escaping, line endings and encoding all vary between producers, so a CSV file that one tool writes is not guaranteed to load in another.

How do I convert JSON to CSV?

Only cleanly if the JSON is a flat array of objects with consistent keys. Take the union of keys as the header row, then write one row per object. Nested values must be flattened or serialised into a cell first — there is no lossless general conversion.

Which should an API return?

JSON, in almost all cases. CSV is worth offering as an explicit export option for users who will open the result in a spreadsheet, but it should be a separate endpoint or a format parameter, not the default response type.

Related Resources

Related Resources