OnlineTextLab
Esc

CSV vs JSON: Structure, Types, Size and When to Use Each

Updated 6 min read How we check our guides

Use CSV when your data is one flat table and a person or a spreadsheet will read it. Use JSON when records have nesting, optional fields, or types you need to keep. If you have millions of JSON records, use newline-delimited JSON rather than one large array. Most of the trouble people have with these formats comes from picking one, then asking it to do the other’s job.

The real difference is the shape of the data

CSV describes a grid. Every row has the same columns, and a cell holds one piece of text. There is nowhere to put a list of three phone numbers except a second table, a repeated column, or a value such as 555-0101;555-0102 that your code must split later.

JSON describes a tree. A record can contain an array of objects, each with its own fields, and two records in the same file do not have to share a shape:

{"id": 1, "name": "Ada", "phones": ["555-0101", "555-0102"], "address": {"city": "London"}}
{"id": 2, "name": "Grace", "phones": []}

Flattening that into CSV forces a decision. Our JSON to CSV converter shows both options. By default it writes a nested object into a single cell as JSON text, so {"b":{"c":2}} becomes a cell containing {"c":2}. With “Flatten nested objects” on, it makes a column called b.c. Arrays stay as JSON text in one cell either way, because no column layout can represent a list of unknown length without inventing columns.

Types: CSV has none

The JSON grammar in RFC 8259 has strings, numbers, booleans, null, objects and arrays. RFC 4180, the closest thing CSV has to a specification, has only text. Everything else is a guess made by whatever reads the file.

Those guesses cause real damage:

Value in the CSVWhat can go wrong
02134 (US ZIP code)Read as the number 2134, losing the leading zero
12345678901234567890Too many digits for a double, so the last digits change
empty cellCould mean empty string, null, zero, or “not collected”
trueStays the text “true” unless something converts it
2026-03-04March or April? A spreadsheet may turn it into a date serial

We ran a row with id=1, zip=02134, big=12345678901234567890, ok=true, e=1e5 and x=1.50 through our CSV to JSON converter with “Infer numbers, booleans, and null” on. The output was "id": 1, "zip": "02134", "big": "12345678901234567890", "ok": true, "e": "1e5" and "x": 1.5. The leading zero survived, and the 20-digit number stayed as text, because the inference rule refuses any value that would change when stored as a number. But 1.50 still lost its trailing zero, which is the sort of thing that matters for prices. Leave inference off for identifiers, account numbers and prices stored as text.

JSON is not immune. RFC 8259 notes that software commonly stores numbers as IEEE 754 doubles, so integers beyond 2^53 lose precision in JavaScript and many other parsers. Send long identifiers as strings in JSON too.

Size: CSV wins, and compression narrows the gap

JSON repeats every key in every record. We generated 1,000 records with five short fields (id, name, email, active, score) and measured them:

FormatRaw bytesGzipped bytes
JSON array83,0808,584
Newline-delimited JSON83,0798,581
CSV40,1065,663

Uncompressed, the CSV is less than half the size. Gzipped, it is about two thirds of the size, because compression is very good at removing repeated keys. The ratio changes with your data: long key names widen the gap, and long text values shrink it. If the file travels over HTTP with compression on, size alone is rarely a good reason to choose CSV.

Streaming: the part people find out too late

Processing a large file means reading a record, handling it, and letting it go, without holding the whole file in memory.

CSV seems made for this, since each line is a row. There is one catch. A quoted field may contain a line break, so splitting on newlines is not safe. The file "line one⏎line two",2 is one record on two physical lines, which also means you cannot jump to the middle of a CSV and be sure you are at a row boundary. See how CSV escaping works for the detail.

A JSON array is the worst case. JSON.parse in JavaScript and json.load in Python need the whole document before they return anything. Streaming parsers such as ijson in Python exist, but they are more code and slower.

Newline-delimited JSON fixes this. Each line is a complete JSON value, and JSON escapes line breaks inside strings as \n, so a raw newline can only mean “end of record”. This is the only one of the three where splitting a file on newlines is always safe, which also makes it easy to process in parallel, to append to, and to resume with ordinary tools:

grep '"status":"failed"' events.ndjson | wc -l

Which to choose

A finance colleague needs the numbers. CSV, or better, an actual Excel file. If precision or leading zeros matter, read about Excel’s habits first, because opening a CSV by double-click applies its type guessing to every column.

A public or internal API. JSON. Clients get types, optional fields and room to add fields later without breaking anyone.

Exporting a database table for another system. CSV if the table is flat and both sides agree on encoding and null handling. PostgreSQL’s COPY and MySQL’s LOAD DATA both read it quickly. Agree on how null is written before you start.

Application logs and event streams. Newline-delimited JSON. Events vary in shape, and you want to append and grep.

Configuration a person edits. Neither. JSON has no comments and CSV has no structure. Look at YAML or TOML, and read about YAML’s pitfalls before you commit to it.

Analytics on hundreds of millions of rows. Neither again. Columnar formats such as Parquet carry a schema, compress far better and let a query read only the columns it needs. CSV and JSON are for moving data between systems, and both are poor for scanning it repeatedly.

Data you need to validate. JSON has JSON Schema. CSV has no equally common equivalent, so validation usually means custom code.

Converting between them without losing data

Going from CSV to JSON is safe if you treat everything as a string and convert only the columns you know. Going from JSON to CSV loses information whenever a field is nested or optional, so check these before trusting the result:

  1. Column union. Our converter builds its header from every key found in any record, so a key that appears once still gets a column. Some tools read only the first record and silently drop the rest.
  2. Missing versus null. Both become an empty cell, and you cannot tell them apart when you convert back.
  3. Stray quotes in the source. A CSV field such as 5" screen is not valid under RFC 4180, because a quote inside a field must have the whole field quoted. Parsers disagree on what to do. When we tested it, Python’s csv module and our converter both kept the text intact, but a parser that treats any quote as the start of a quoted section will merge the next row into that cell. If a row count comes out short after a conversion elsewhere, look for this first.

Our converters run in the browser and suit pasted data or small files. For a multi-gigabyte export, use a command line tool such as Miller, or jq with its --stream option, which process data as it arrives instead of holding it all in memory. To check a JSON document is well formed before you convert it, the JSON validator tells you whether it parses and summarizes what it found.