Parquet to JSON Lines Converter
Turn a stored file back into a stream. One compact object per line, types read from the Parquet schema, and no array to hold in memory.
To convert Parquet to JSON Lines, drop your .parquet file above. DuckDB running in your browser reads it using the schema stored in the file, and each row becomes one compact JSON object on its own line, with no wrapping array. Types come straight from the schema, so nothing is inferred and nothing can be inferred wrong.
Want to filter rows before exporting? Open the app
Going back the way you came
Most conversions on this site move data toward storage. This one moves it back out, and there are three reasons people need it.
The first is a system that only takes NDJSON: a search index, a document store, an ingest endpoint that was written for logs. Parquet is the wrong shape for all of them and JSON Lines is the shape they expect.
The second is inspection with line-oriented tools. Once the data is one record per line, grep, head, wc and jq all work, and a quick question about a Parquet file becomes a one-liner instead of a Python session.
The third is a diff. Two Parquet files cannot be usefully compared with a text diff and two NDJSON files can, provided the row order is stable.
The one conversion where consistency is guaranteed
Everywhere else on this site, keeping a column to one type is a rule the conversion has to enforce by reading every value. Here it is free: the Parquet file already declares each column's type, and every value in that column already conforms.
So an INT64 column emits JSON numbers on every line, a VARCHAR emits strings on every line, a BOOLEAN emits true and false, and a DATE emits ISO strings. There is no sampling and no inference, which means the schema-mismatch failure that kills a warehouse load simply cannot occur.
The single exception is a very large INT64, which exceeds the exact range of a JSON number. Those are emitted as strings rather than being silently rounded, and it is the one place where the output type differs from the schema type on purpose.
Worked example
Two rows of an orders file:
{"order_id":"ORD-00001","placed_on":"2026-01-08","region_code":"01","units":12,"revenue":1840.5,"paid":true,"note":null}
{"order_id":"ORD-00002","placed_on":"2026-01-09","region_code":"02","units":3,"revenue":275,"paid":false,"note":"PO 8841"}
Every key is present on every line, including note where the value is null. That is what a fixed-schema consumer needs: a missing key and a null value mean different things, and a Parquet column that is null for a row is present-and-null rather than absent.
Size, and the honest limit
This is the conversion where the size mismatch is starkest. A Parquet file is compressed and columnar; its NDJSON equivalent repeats every key on every line and stores every value as text. A ten megabyte Parquet file can easily become several hundred megabytes of NDJSON.
Everything here happens in your tab's memory, so that expansion is the real constraint rather than the input size. A Parquet file of a few tens of megabytes is comfortable; something much larger is a job for a pipeline, and running DuckDB's own COPY command on a machine with disk is the right tool for it.
The result panel reports the row count, which is the quickest sanity check that the export is the size you expected before you wait for a download.
Why it matters that this runs locally
Every hosted converter for these formats asks you to upload the file. That is a straightforward trade for a photo and a bad one for a data file, because the data files people convert are extracts: customer tables, transaction detail, payroll, event logs with identifiers in them.
Here the engine is compiled to WebAssembly and runs inside the page. The file is read by JavaScript in your tab, the output is produced there, and the download comes from memory. Nothing is sent, stored or logged, and once the page has loaded the whole thing works with the network off.
The practical limit is your tab's memory rather than an upload quota. For files well past a hundred megabytes the full editor streams and is the better route.
Frequently Asked Questions
Can the types be inconsistent between lines?
No, and this is the one page where that is guaranteed rather than enforced. The Parquet file declares each column's type and every value already conforms, so there is no sampling and no inference for a mismatch to come from.
Why is a large integer emitted as a string?
Because JSON numbers are IEEE-754 doubles and lose precision past about fifteen significant digits. A large INT64 written as a number would be silently wrong, so it is written as a string and stays exact. It is the only place the output type deliberately differs from the schema.
Are keys present on every line even when null?
Yes. A Parquet column that is null for a row is present and null rather than absent, and a fixed-schema consumer treats a missing key differently from a null value.
How much bigger will the NDJSON be?
Often by an order of magnitude or more. Parquet is compressed and columnar; NDJSON repeats every key on every line and stores every value as text. A ten megabyte Parquet file can become several hundred megabytes.
What is the practical size limit?
Your tab's memory, and the expansion above is what fills it. A Parquet file of a few tens of megabytes is comfortable. For anything much larger, DuckDB's own COPY command on a machine with disk is the right tool.
How are struct and list columns handled?
They come through as nested JSON in the object, which JSON Lines can express natively. This is one of the few targets where Parquet's nested types survive with their structure intact rather than being flattened.
Turn the stored file back into a stream
One object per line, types from the schema, nothing uploaded.
Back to the converter