JSON to CSV Converter

Turn a JSON array of records into a spreadsheet-ready table, or read a CSV table back into JSON. Nested objects become dot-notation columns, and commas, quotes and newlines inside values are quoted correctly in both directions.

Quoting follows RFC 4180: a field containing the delimiter, a double quote, a carriage return or a newline is wrapped in quotes, and inner quotes are doubled. Everything runs in your browser — nothing is uploaded.

Nothing converted yet.
Paste JSON or CSV above and choose a direction.

Two formats with very different jobs

CSV is a table: a header row of column names followed by rows of values, all of them text. JSON is a tree: objects inside arrays inside objects, with real types for numbers, booleans and null. Converting between them is therefore not a simple re-encoding — it is a change of shape, and knowing where information is lost is the difference between a clean export and a support ticket.

The direction people need most often is JSON to CSV, because an API returns records and someone wants them in a spreadsheet. You pull a list of orders with the API tester, paste the response body here, and hand the result to whoever asked. The reverse is just as useful in reverse: a colleague sends a CSV of test fixtures and you need it as a JSON array to feed into a request body or a seed script.

How nesting is flattened

A table has no concept of nesting, so a nested object has to be projected onto columns. This converter uses dot notation: a record whose address object contains city produces a column named address.city. Arrays are flattened by index, so a tags array yields tags.0 and tags.1. It is not pretty, but it is unambiguous and it reverses cleanly — converting back rebuilds the objects, and a complete run of numeric keys starting at zero is rebuilt as an array rather than as an object with numeric keys.

The column set is the union of every key across every record, in the order the keys are first seen. That matters because JSON records are not obliged to be uniform: if half your objects have a discount field and half do not, the column exists and the rows that lack it are empty. If records vary wildly, the CSV will be wide and sparse — a signal that the data is not really tabular and that a flat export may be the wrong idea rather than a formatting problem to solve.

CSV is harder than it looks

"Comma-separated values" sounds like a format you could implement with split(','), and that belief is responsible for an enormous number of broken exports. The rules that actually matter come from RFC 4180:

  • A field containing the delimiter, a double quote or a line break must be enclosed in double quotes.
  • Inside a quoted field, a double quote is written twice: "he said ""hi""".
  • A quoted field may contain literal newlines, so one record can span several physical lines. Reading a CSV line by line is therefore wrong.
  • Line endings are CRLF in the specification, but LF is universal in practice and both must be accepted.
  • Whitespace next to a delimiter is significant and is not trimmed.

A field like Jones, "Bob", said:\nhello exercises all of it at once — delimiter, quotes and a newline in a single value. The writer here emits it correctly and the parser reads it back identically, which is the only test that really matters for a converter of this kind.

What CSV cannot represent

JSONIn CSVConsequence
nullEmpty fieldIndistinguishable from an empty string
""Empty fieldSame as above
Missing keyEmpty fieldAlso the same
42 and "42"42Type is lost; inference guesses on the way back
Nested objectDot-notation columnsReversible, but wide
Array of objectsIndexed dot columnsReversible; explodes in width

The type-inference selector controls what happens on the way back. With inference on, 42 becomes a number, true becomes a boolean and null becomes null — usually what you want, and occasionally wrong: a product code like 0012 or a phone number beginning with a plus sign is not a quantity. Switch to "keep as strings" when the data is full of identifiers, then fix the handful of genuinely numeric columns afterwards. It is the same class of problem as the type coercion described on the YAML to JSON page, and the same defence applies: know which of your fields are identifiers rather than numbers.

Practical notes

Choosing a delimiter

Comma is the default and the one the format is named after. Semicolon is what spreadsheet software expects in locales where the comma is the decimal separator, which is why a perfectly valid comma-delimited file opens as a single column for a colleague in Berlin or Paris. Tab-separated output avoids the ambiguity almost entirely, because tabs are rare inside real values, and pipe is a common choice in data pipelines. Pick the delimiter that appears least often in your data and the quoting rules will have less work to do.

Encoding and the byte-order mark

Write CSV as UTF-8. If a recipient opens the file in a spreadsheet and sees mojibake where accented characters should be, the application guessed a legacy code page; prefixing the file with a UTF-8 byte-order mark usually fixes it, at the cost of a stray character for anyone parsing it programmatically. This tool produces plain UTF-8 without a BOM, which is the right default for machines.

The formula injection trap

A CSV cell beginning with =, +, - or @ is interpreted as a formula by spreadsheet applications. If your data comes from users, an exported file can therefore execute something on the recipient's machine — a genuine vulnerability class known as CSV injection. If you are generating exports from untrusted input in production code, prefix such cells with an apostrophe or a space before writing them. The same instinct that makes you escape output for the web, covered on the HTML encoder page, applies here in a different clothing.

Getting good input in the first place

A JSON payload that will not convert is usually a payload that is not an array of records: an API often wraps its results in an envelope such as {"data": [...], "meta": {...}}. Extract the array first — the JSON formatter makes the structure obvious in a second — and paste that. If the export from two different days disagrees, run both through the diff checker to find the changed rows, and if you need to prove two exports are identical, the hash generator answers it in one step. When an upload of your CSV is rejected outright, check the Content-Type header you sent; a 415 Unsupported Media Type means the server wanted text/csv and got something else.

Frequently asked questions

What input does the JSON to CSV direction expect?

An array of objects is the natural case. A single object is converted to a one-row table, and an array of scalars becomes a single column named value. An object wrapping the array in an envelope has to be unwrapped first.

Can a CSV value really contain a line break?

Yes, inside a quoted field, and it is common in address and comment columns. This is why splitting a CSV on newlines before parsing it is a bug rather than an optimisation.

Why did my leading zeros disappear?

Type inference turned the text into a number. Switch the selector to keep values as strings, and be aware that spreadsheet software does the same thing on import for its own reasons.

Does column order match my JSON?

Yes. Columns appear in the order their keys are first encountered while scanning the records, so the first object's field order leads and later objects contribute any extra fields at the end.

Is there a row limit?

No hard limit, but everything runs in a browser tab, so tens of megabytes will be slow. For very large exports, do the conversion in a script.

Related tools and reference