jsonlkit.com
JSONL (JSON Lines) utilities, in the browser
Say hi →

JSONL to CSV Converter

updated 28 May 2026

JSONL to CSV converter. Flatten nested objects with dot.notation and export a CSV ready for Excel, Google Sheets or BigQuery. Up to 1 GB, runs in your browser, nothing uploaded.

Need the other direction? → CSV → JSONL

100% client-side. Your file never leaves your browser. No upload.

Convert

Drop a .jsonl file here, or

JSONL to CSV Converter

Flatten nested JSONL / NDJSON into a flat CSV table. Columns are inferred automatically using dot.notation for nested keys. Open the output in Excel, Google Sheets, BigQuery, or pandas.

What this tool does

It reads JSONL (or NDJSON) — one JSON object per line — and rewrites it as a CSV table. Nested objects flatten into dot.notation columns, arrays spread across indexed columns (tags.0, tags.1), and the result is RFC 4180-compliant CSV you can hand to anything that reads spreadsheets. The conversion runs entirely in your browser; nothing is uploaded.

The intent this tool closes is the everyday one: "I have a JSONL file and I need it as a flat table I can open somewhere else." That "somewhere else" is usually Excel, Google Sheets, BigQuery, Snowflake, Athena, DuckDB, or a pandas DataFrame — all of which want flat columns, not nested JSON.

When you'd reach for it

How the conversion works

Three stages run on every click of Convert.

1. Parse, line by line

Each non-empty line is parsed as a standalone JSON value. Blank lines are silently skipped. If a line isn't a JSON object — for example a bare string, number, or top-level array — it's listed under Errors and dropped, because there are no keys to map to column headers. The rest of the file still converts; one bad line doesn't abort the whole run.

2. Flatten each record

Each object is walked recursively. Every leaf value becomes one entry in a flat key→value map; the separator (dot, underscore, or slash) joins the path parts together.

{"a": 1}              → a
{"a": {"b": 1}}       → a.b
{"tags": ["x", "y"]}  → tags.0, tags.1
{"a": {}}             → a (empty cell)

If you switch Nested to JSON-encode cell, the walker stops at the first nested level — any sub-object or sub-array is written as a single JSON string in one cell. Use that when you'd rather preserve structure than explode it across many columns.

3. Build the header, then emit rows

The CSV header is the union of every column key seen across every record, listed in the order keys first appear. That's why the converter has to read all input before writing any output: the column set for row 1 isn't known until the last row has been parsed. Rows are then emitted in column order. Missing keys become empty cells. Each value is escaped per RFC 4180: a cell containing the delimiter, the quote character, or a line break gets wrapped in quotes, and any embedded quote is doubled.

Options reference

Delimiter

Character between columns. Comma for standard CSV. Semicolon for European Excel locales that interpret comma as a decimal mark. Tab when your values are full of commas — tabs almost never collide with real data, so quoting stays minimal. Pipe for ad-hoc scripts and old ETL tools.

Quote

The wrapping character used only when a value needs escaping. Stick with double-quote; every spreadsheet, every warehouse loader, and pandas expects it. Single-quote is there for the rare downstream parser that demands it.

Header

Yes writes a first row with the column names. No writes data only — useful when you're appending to a table that already has a header.

Nested

Flatten recursively expands every nested object and array into its own column. JSON-encode cell keeps each nested value as a single JSON string in one column — much friendlier when records have unpredictable nesting or large variable-length arrays.

Separator

The character joining flattened key parts. Dot is conventional. Underscore is friendlier if you'll run SQL against the result, since column names like user_id don't need backtick quoting. Slash is useful when your original keys themselves contain dots.

EOL

Line terminator. LF for Unix tools, pandas, DuckDB, BigQuery, Snowflake. CRLF for legacy Windows Excel and Power Query flows that complain about LF-only files.

BOM

Prepends a UTF-8 byte-order mark (U+FEFF). Turn it on if you'll open the file in Excel and your data has non-ASCII characters — without the BOM, Excel often decodes the file as Windows-1252 and turns "café" into "café". Turn it off for everything else; BigQuery, Snowflake, pandas, and DuckDB prefer raw UTF-8.

Output format

Example

Input (JSONL):

{"id": 1, "user": {"name": "Ada"}, "tags": ["admin", "dev"]}
{"id": 2, "user": {"name": "Linus"}, "notes": "Active"}

Output (CSV, defaults):

id,user.name,tags.0,tags.1,notes
1,Ada,admin,dev,
2,Linus,,,Active

Header is the union of keys across both rows in first-seen order. Row 2 has no tags, so those cells are empty. Row 1 has no notes, so that cell is empty.

Recipes by intent

Open in Excel without mojibake

Delimiter comma, EOL CRLF, BOM Yes. Save the file, double-click. Cyrillic, accented Latin, and CJK characters all survive.

Load into BigQuery / Snowflake / Athena

Delimiter comma (or tab — both work; tab survives messy text better), EOL LF, BOM No, Header Yes. Upload, let the warehouse autodetect schema from the header row.

Read with pandas or DuckDB

Defaults are fine. Nested Flatten, dot separator, comma delimiter, LF, no BOM. Column names mirror your dot-paths exactly, so df["user.name"] and SELECT "user.name" both work.

Keep nested structure intact

If your records contain unpredictable nested arrays — chat messages, tag lists, event payloads — set Nested to JSON-encode cell. You'll get one column per top-level key, with the nested value stored as a JSON string the downstream code can parse on demand.

Round-trip without losing fidelity

Pick Tab delimiter and Nested JSON-encode cell. Tabs almost never appear inside values, and JSON-encoded cells preserve the full original structure — you can reverse the transformation later if you need to get back to JSONL.

SQL-safe column names

Set Separator to underscore. Flattened keys become user_name instead of user.name, so you don't need to quote them in SELECT statements.

Limits and performance

Errors and how to fix them

Line N: invalid JSON

The line isn't parseable. Common causes: a trailing comma in an object, single-quoted keys, JavaScript-style comments, or a record split across multiple lines. Drop the file into the JSONL Validator to locate every bad line in one pass.

Line N: expected JSON object, got string / number / array

CSV is a table of records, so the top level of each line must be an object. If your input is NDJSON of arrays, wrap each in a small object first — for example {"row": [1, 2, 3]} — or use Nested JSON-encode cell after wrapping.

Excel shows everything in one column

You opened a comma-CSV in a European Excel locale that expects semicolon. Re-export with Delimiter: semicolon, or in Excel use Data → From Text/CSV and pick the delimiter manually.

Non-ASCII characters look corrupted

Re-export with BOM: Yes. Excel uses the BOM to recognize UTF-8; without it, older versions fall back to the local code page.

Column order isn't what I expected

Columns appear in first-seen order. If keys you care about live in later rows, they'll show up further right. Reorder in the spreadsheet after import, or move a "canonical" record to the top of your JSONL so all keys appear early.

The browser tab freezes during a big conversion

The conversion itself is usually fine; what freezes is rendering the result into a textarea. Use Download directly after Convert — the file is written without rendering the whole string in the DOM.

FAQ

Does my data get uploaded anywhere?

No. The script runs in your browser. You can disconnect from the network and it still works. Safe for API logs, customer data, and anything else you don't want crossing a server.

Will null values round-trip?

No. CSV has no concept of null; both null and a missing key become empty cells. If you need to preserve the difference, use JSON-encode cell mode, or convert via JSONL → JSON and ingest the array directly.

Why dot-notation instead of separate child tables?

Because the destinations people actually use — Excel, Sheets, BigQuery, pandas — want a single flat table. Splitting one JSONL into multiple normalized CSVs is a different job, usually done in code rather than a one-shot converter.

I have a JSON array file, not JSONL — can I convert it here?

Convert it to JSONL first with JSONL ↔ JSON, then paste the result here. The error messages on this tool are tuned for line-delimited input, which is why it doesn't accept arrays directly.

How many records and columns am I getting?

The status bar under the widget shows both: "Converted N rows across M columns", plus a count of any skipped lines. Useful for sanity-checking before you import somewhere expensive.

Related tools