Paste JSONL
Upload File
From URL

Click to select or drag & drop a .jsonl / .ndjson / .json file

Next step: pull this data into spreadsheets or a data warehouse on a schedule — Coupler.io automates it. (affiliate link)

All conversion runs in your browser. Your JSONL is never uploaded to any server.

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:

Two cards side by side. On the left a JSON array wraps two objects in square brackets and separates them with a comma. On the right the same two objects sit on separate lines with no brackets and no separating commas.
The wrapper is the only difference. The records themselves are identical, which is why a JSONL file and a JSON array can be converted by the same rules.

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.

Two JSON Lines records whose s values are a,b and c,d, feeding through the rules that a line break ends a record while a comma inside a value does not, producing a CSV with the header s and two quoted rows.
Two lines in, two rows out. The commas inside the values are quoted rather than split, because only the line break separates records.

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 inputCSV outputWhat 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.

Two ragged JSON Lines records, the first with keys a and b and the second with keys b and c, mapping to a CSV grid whose header is a, b, c with an empty cell left in each row where a key is missing.
The ragged-keys row of the table above, drawn. One header is computed for the whole file, and a missing value leaves its cell empty rather than pulling the following columns one place to the left.

Output options

SettingJSONL inputCSV 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.

The same records fed in twice, once as two JSON Lines and once as a JSON array, with both paths converging on one output showing the CSV a,b then 1,2 then 3,4, labelled byte for byte.
The test this page is built on. Both inputs hold the same two records, so both must land on the same bytes — and on all 24 shapes below they do.

That check was run against the converter above on 24 JSONL shapes. All 24 produced output identical to the array form:

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 inputCSV 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 inputCSV 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 inputCSV 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