JSON Lines to Excel Converter
Open a log export in a spreadsheet. Each line becomes a row, nested fields become dotted columns, and the numbers arrive as numbers.
To convert JSON Lines to Excel, drop your .jsonl or .ndjson file above. Each line becomes one spreadsheet row, keys become columns, nested objects flatten with dot notation, and each column is written with a single cell type. ISO dates become real date cells, the header row is frozen and the widths fit. Built in your browser.
Want to filter the events first? Open the app
Where JSON Lines files come from
Almost always a machine. An application log, a Kafka topic dumped to disk, an analytics export, a warehouse extract, a batch API response. Nothing produces JSON Lines by hand, which means the files are usually large and always uniform.
And the person who needs to look at them frequently does not work in a terminal. An analyst wants to pivot the events by day, a support lead wants to filter to one customer, a manager wants a chart. All three want a spreadsheet.
The obstacle is that jq into CSV loses every type on the way, so the durations arrive as text and the pivot will not sum them.
Worked example
Two lines of an order export with a nested customer:
{"order_id":"ORD-00001","placed_at":"2024-05-13T01:17:00Z","status":"shipped","customer":{"id":4188,"name":"Katherine Johnson","city":"Osaka"},"items":8,"total":2151.83,"gift":false}
{"order_id":"ORD-00002","placed_at":"2024-08-10T11:39:00Z","status":"delivered","customer":{"id":3737,"name":"Ada Lovelace","city":"Berlin"},"items":1,"total":1783.46,"gift":true}
And the workbook, column by column:
- order_id text. It has a prefix, so it is an identifier.
- placed_at text, because it is a timestamp with an offset rather than a plain date, and interpreting it would mean choosing a timezone.
- status text.
- customer.id numeric, from the nested object.
- customer.name and customer.city text, also from the nested object.
- items and total numeric, so they sum and chart.
- gift real boolean cells showing TRUE and FALSE, which COUNTIF understands.
Nine columns from a record with six top-level keys, because the nested customer contributed three of them. That expansion is visible in the preview before you download anything.
One type per column, decided across every line
The type is decided from every line in the file, not from the first one and not per cell. That matters more here than anywhere else, because JSON Lines files are long and their inconsistencies are late: a field that is a number on the first ten thousand lines and a string on line ten thousand and one.
When that happens the column becomes text and every value keeps its exact spelling. The alternative is a column Excel marks with a green triangle on the inconsistent cells, which cannot be sorted as a range or filtered numerically.
Booleans are written as boolean cells rather than the text true, and exact ISO dates become real date cells with the serial computed by UTC arithmetic so no timezone can move them by a day.
Flattening, and the row count guarantee
Nested objects flatten into dotted columns. Nesting past four levels stays as JSON text in one cell, because a header row of five-part names is not something anyone can read in a spreadsheet.
An array of objects also stays as JSON text in one cell rather than being spread into extra rows. That keeps a promise worth stating plainly: the workbook has exactly as many rows as the file had lines. A spreadsheet where the row count silently differs from the source is one whose totals nobody should trust.
Both decisions are reported under the result with a count, so you know how many fields were affected rather than discovering a cell full of braces later.
Size, and when to stop
Excel's own limit is 1,048,576 rows and this does not add one below it. The widget handles files up to 100 MB, which for a typical NDJSON export is a few hundred thousand lines.
Past that, a spreadsheet is the wrong container regardless of what the tool can produce. A file of two million events belongs in Parquet or in a database, both of which are one click away, and the useful spreadsheet is the aggregate rather than the raw events.
Frequently Asked Questions
Does it need the file to be named .jsonl?
No. Anything with one JSON value per line works, whatever the extension is. NDJSON, .jsonl, .json holding lines, or pasted text are all read the same way, and a note tells you when the content was read as lines rather than as one document.
How are nested fields handled?
They flatten into dotted columns, so a nested customer becomes customer.id, customer.name and customer.city. Nesting past four levels stays as JSON text in one cell, because a spreadsheet header of five-part names is unreadable.
Does the workbook have the same number of rows as my file has lines?
Always. An array of objects inside a record is kept as JSON text rather than spread into extra rows, precisely so that the row count matches. A spreadsheet whose row count silently differs from the source is one whose totals cannot be trusted.
Why is one numeric-looking column text?
Because at least one line in the file has a value in it that does not survive as a number, which in a long export is common and usually late. The whole column stays text so it is consistent, which is better than a column with green triangles on a few thousand cells.
Do timestamps become date cells?
Only exact YYYY-MM-DD values do. A timestamp carrying a time and an offset stays text, because turning it into an Excel date means choosing a timezone and Excel has no concept of one to record the choice in.
How big a file can it take?
The widget handles up to 100 MB, which is a few hundred thousand lines of typical NDJSON, and Excel's own ceiling is just over a million rows. Past that a spreadsheet is the wrong container and Parquet or a database is the better destination.
Open the log export in a spreadsheet
Typed cells, flattened fields, a frozen header, and the same row count as your file.
Back to the converter