Tools · NDJSON

NDJSON to CSV

The keys become the header, one record becomes one row, and a nested object is decided out loud: a packed cell, not a silent flattening.

no signup · runs entirely in your browser · ⌘V works anywhere on this page
See it done · 10 s
NDJSON to CSVThe same records; Convert, CSV writes the keys as the header and one row per record — a nested object packed into its cell. · 10 s

What you get

  • Writes the sample's 4 parsing records as CSV under 9 columns — every key any record used, in the order they appeared
  • Packs a nested object into its cell as JSON, quoted so the CSV survives a spreadsheet; the app opens that cell as nested rows
  • Quotes a cell that holds a comma, a quote or a line break the way RFC 4180 writes it
  • Names the broken line — 1 in the sample — and leaves it out with its number, rather than writing half a row
  • Copies or downloads the .csv; the app has the table, the filter and Compare

What it will not do

  • Flatten nested objects into dotted columns. A nested value is one cell, opened in the app when you want the rows.
  • Invent a column order. The first record’s keys come first, then any key a later record adds.
  • Send your text anywhere. The page is static and the engine runs in this tab — open the network panel and watch it stay empty.

What becomes a column

Every key seen → a column
{"id":1,"a":"x"} {"id":2,"b":"y"} {"id":3}id,a,b 1,x, 2,,y 3,,
A nested object → a packed cell
{"id":1,"meta":{"k":"v"}} {"id":2,"meta":{"k":"w"}} {"id":3,"meta":{}}id,meta.k,meta 1,v, 2,w, 3,,

The cell holds the object as JSON, quoted the way RFC 4180 writes a quote inside a cell. In the app that cell opens as nested rows.

A comma or a quote in a value
{"msg":"a, b"} {"msg":"say \"hi\""} {"msg":"plain"}msg "a, b" "say ""hi""" plain
A broken line

Named by line; left out of the CSV with its number said, never written as a half row.

The sample

What the first sample opens — a real file, not an illustration written for this page.

checkout-api.ndjson
{"ts":"2026-04-21T14:32:08.412Z","level":"info","msg":"stripe.charge.completed","amount":17054,"order_id":"ord_8f3aa19c4d"}
{"ts":"2026-04-21T14:32:07.940Z","level":"warn","msg":"retry.scheduled","attempt":2,"backoff_ms":400}
{"ts":"2026-04-21T14:32:07.813Z","level":"error","msg":"stripe.webhook.signature_invalid","payload":"{\"event\":\"charge.succeeded\",\"id\":\"evt_1PZ3xK\"}"}
{"ts":"2026-04-21T14:32:07.512Z","level":"info","msg":"cart.items.priced","items":2,"total":14900
{"ts":"2026-04-21T14:32:06.301Z","level":"info","msg":"session.token.issued","ttl":3600}

in VS Code

Read as records, then Convert, then CSV — into a new editor, the nested values packed the same way.

unstringify for VS Code14-day trial · Free and Pro

Questions

What happens to a nested object?

It becomes one cell holding the object as JSON, quoted for the CSV. Nothing is flattened, so no information is lost; the app opens the cell as nested rows when you want to read it.

Do all lines need the same keys?

No. The header is every key any record used; a record without a key gets an empty cell there.

What if a line is broken?

It is named by line with its fix and left out of the CSV, with the count on the page. In the app, Fix all rewrites that line and the row joins the table.

Try it on the file that broke your afternoon.

free while in alpha · no signup