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
| JSON | In CSV | Consequence |
|---|---|---|
null | Empty field | Indistinguishable from an empty string |
"" | Empty field | Same as above |
| Missing key | Empty field | Also the same |
42 and "42" | 42 | Type is lost; inference guesses on the way back |
| Nested object | Dot-notation columns | Reversible, but wide |
| Array of objects | Indexed dot columns | Reversible; 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
API Tester
Fetch the records you want to export straight from the endpoint.
JSON Formatter
Unwrap an envelope and confirm you are converting the right array.
YAML to JSON
Bring configuration data into JSON before flattening it into columns.
Diff Checker
Compare two exports and see which rows actually changed.
HTTP Headers
Content-Type, charset and Content-Disposition for file downloads.
415 Unsupported Media Type
What a server returns when it expected text/csv and got JSON.