JSONL to CSV
Paste a JSONL file as it is — one JSON object per line, no outer brackets — and get one CSV table back. Nothing is uploaded, and every behaviour described on this page was measured on the converter above, byte for byte.
What JSONL is, and why the brackets are missing
JSONL (JSON Lines, also written .ndjson) stores one complete JSON value per line. There is no outer array and no comma between records, so a stream can be appended to a line at a time and a single corrupt line does not invalidate the file. A JSON array and a JSONL file holding the same three records differ only in punctuation:
The mapping to CSV is the same in both cases: one record becomes one row, one key becomes one column. That is why the converter accepts either shape, and why it produces the same bytes for both — which is the first thing worth testing rather than assuming.
A line break is the only thing that ends a record
The one place where JSONL is read differently from a JSON array is the record boundary. In a JSON array the separator is a comma; in JSONL it is the line break, and a comma inside a value is data. That single rule decides whether a two-line file becomes two rows or four.
What the converter actually does with your JSONL, measured
The tables below are not descriptions of a rule. Each cell is the literal output the converter above produced for the literal input beside it, taken from the engine that runs this page. The real output uses CRLF line endings; the tables show them as single line breaks so the columns stay readable. Nothing else is altered — quoting, spacing and empty cells are the bytes that come out.
Records, keys and structure
| JSONL input | CSV output | What it settles |
|---|---|---|
{"a":1,"b":2}
{"a":3,"b":4} |
a,b 1,2 3,4 |
One line is one record. No outer brackets, no commas between records. |
{"a":1,"b":2}
{"b":3,"c":4} |
a,b,c 1,2, ,3,4 |
Records with different keys are unioned in first-appearance order. Missing cells are left empty — later columns do not shift left, so a value never lands under the wrong header. |
{"id":1,"user":{"city":"NYC"}}
{"id":2,"user":{"city":"LA"}} |
id,user.city 1,NYC 2,LA |
With Flatten nested on, a nested object becomes dot-path columns. |
42 "alpha" null true |
_value 42 alpha true |
A line may hold any JSON value, not only an object. A bare scalar becomes one cell in a column named _value; null becomes an empty cell. |
{"a":1}
{"a":2}
|
a 1 2 |
Blank lines, a trailing newline, CRLF line endings and a leading byte-order mark are all tolerated and do not change the row count. |
{"a":1}
oops
{"a":2} |
Invalid JSON: line 2 is not one complete JSON value. Unexpected non-whitespace character after JSON at position 8 (line 2 column 1) |
A broken line stops the conversion and is named by number. It is never skipped silently, because a quietly dropped record is worse than an error. |
Captured with the default options: header row on, flatten nested on, comma delimiter.
Output options
| Setting | JSONL input | CSV output |
|---|---|---|
| Header row off | {"a":1,"b":2}
{"a":3,"b":4} |
1,2 3,4 |
| Delimiter: tab | {"a":1,"b":2}
{"a":3,"b":4} |
a b 1 2 3 4 |
| Force quotes | {"s":"plain"}
{"s":"x"} |
"s" "plain" "x" |
| Comma inside a value | {"s":"a,b"}
{"s":"c"} |
s "a,b" c |
The check behind this page: JSONL must equal the array form
There is one property that decides whether a converter really handles JSONL, and it is cheap to test: converting a JSONL file must produce byte-identical CSV to converting the same records as a JSON array. If the two paths disagree, one of them is taking a branch it should not.
That check was run against the converter above on 24 JSONL shapes. All 24 produced output identical to the array form:
- two records with the same keys; a single record; a trailing newline
- CRLF line endings; a blank line in the middle; leading and trailing spaces on a line
- a UTF-8 byte-order mark at the start of the file
- ragged records with different keys
- a nested object on every line
- a comma inside a value; a quote inside a value; an escaped newline inside a value
- non-ASCII text and emoji
- a leading-zero string; a 19-digit integer
- an array on every line; a bare number, string,
nulland boolean on its own line - a record that itself has a key named
_value - a single object that is not a list; a record with a
nullvalue;0next to an empty string
The last few are the ones that catch implementations out, because a line holding a bare 42 or null is valid JSONL but is not an object. A parser that only accepts lines starting with a brace reads those files as broken JSON and fails — which is exactly the kind of difference this check exists to expose.
The 27-shape fixture corpus, published with the runner
Most converters describe their rules. This one publishes the bytes. The corpus behind the converter on this site is public: json-to-csv-edge-cases holds 27 input shapes, the literal CSV each one produces (raw bytes, CRLF, no cleanup), a table of all 27 outcomes, and a runner that points any converter at the fixtures:
node tools/check.mjs -- <your converter>
Your command reads JSON on stdin and writes CSV on stdout; the runner reports one line per fixture with a byte-level diff for anything that does not match. The converter on this page passes 27 of 27 byte for byte with the default options, and 24 of 24 on the JSONL equality check above. A difference is not automatically a bug — several cases are choices where two reasonable converters decide differently — but you should know which choice your tool made, and that is hard to do without fixtures.
Where JSONL to CSV goes wrong
These are measured limits of this converter, not disclaimers. Each one is a place where the right fix is upstream of the conversion.
An array value stays one cell, it does not become columns
| JSONL input | CSV output |
|---|---|
{"id":1,"tags":["red","blue"]}
{"id":2,"tags":["green"]} |
id,tags 1,"[""red"",""blue""]" 2,"[""green""]" |
A list has no single-column equivalent, so it is written into the cell as JSON text with its quotes doubled. A dataset built around arrays of objects is the wrong shape for one CSV table; expand it into rows first, or pick the fields you need.
A line that is an array is flattened into numbered columns
| JSONL input | CSV output |
|---|---|
[1,2,3] [4,5,6] |
0,1,2 1,2,3 4,5,6 |
Arrays on a line are valid JSONL, and with Flatten nested on they expand to columns named by index. That is coherent but rarely what you want; turn flattening off and each line becomes a single cell instead. Note also that a one-line file is read as ordinary JSON, so a single-line array is treated as a list of records rather than as one array record — the JSONL reading starts at the second line.
A number above 253 is already wrong before the CSV exists
| JSONL input | CSV output |
|---|---|
{"id":12345678901234567890}
{"id":1} |
id 12345678901234567000 1 |
The digits are lost when JSON is parsed, not when CSV is written — the same loss happens in every JavaScript-based tool, and in most others. If a long identifier has to survive, it must be a quoted string in the source JSONL: "id":"12345678901234567890".
The output is UTF-8 with no byte-order mark
That is the right choice for pandas, psql, jq and most command-line tooling. Excel instead guesses the encoding from the system locale, which is why accented text and emoji can arrive mangled when you double-click the file. The fix belongs in the import path (choose UTF-8, or import via Data → From Text/CSV), not in the file.
A value starting with =, +, - or @ is a live formula in Excel
Quoting the field does not stop it: with Force quotes on, a value of =1+1 is written as "=1+1", which Excel still evaluates. If your JSONL comes from an untrusted source, prefix those cells or import the CSV as text.
One CSV is one table
JSONL files are often deliberately heterogeneous — a log stream where each line type has different fields. Converting such a file gives a wide, sparse table: the columns are the union of every key seen anywhere in the file, and most rows fill only a few of them. That is a faithful conversion, but if you only want one line type, filter the file first.
FAQ
What is JSONL?
JSONL (JSON Lines, also called NDJSON) is a text format where each line is one complete JSON value, with no outer array and no commas between records. A file holding three records is three lines, each one starting with a brace.
How is JSONL different from a JSON array?
A JSON array holds the same records wrapped in one pair of brackets and separated by commas, like [{"a":1},{"a":2}]. A JSONL file holds {"a":1} and {"a":2} on two lines. This converter reads both, and for the same set of records it writes byte-identical CSV; that equality is one of the things measured on this page.
Do I have to wrap my JSONL in brackets before pasting it?
No. Paste the lines as they are. If two or more non-empty lines each hold a complete JSON value, the input is read as JSONL. A single line is read as ordinary JSON, so a one-line array is still treated as an array rather than as one record.
Can I upload a .jsonl or .ndjson file?
Yes. The upload tab accepts .jsonl, .ndjson, .json and .txt. The file is read in the browser and is never sent to a server.
How large a JSONL file can this converter handle?
There is no row cap and no upload limit, because the conversion runs in the memory of your own browser. A 5,000-record file converts to 5,001 CSV lines in the same tab. Files of tens of megabytes depend on the memory of the device you are using.
What happens if one line of the JSONL is broken?
The conversion stops and the message names the line, for example: Invalid JSON: line 2 is not one complete JSON value. A broken line is never skipped silently, because a silently dropped record is worse than an error.
Will leading zeros in my data survive the conversion?
Yes, if the value is a quoted string in the JSONL, like "02116". If a long number is written unquoted, JSON itself has already rounded it before this tool sees it: 12345678901234567890 arrives as 12345678901234567000.
Can I get a separate CSV file per record?
No. One CSV file is one table. Every record becomes a row and the columns are the union of the keys found in the file.
Related
- JSON to CSV converter — the same engine, with the full option set and the 27-shape corpus explained
- How to convert a JSON to CSV — the step-by-step walkthrough with measured output
- JSON to SQL — generate
CREATE TABLEandINSERTstatements instead of a flat file - JSON to Excel — write a real
.xlsxworkbook rather than a CSV - CSV to JSON — the reverse direction