JSON to Parquet
How to convert JSON to Parquet in your browser
rows.page converts JSON or JSONL files up to 1.5 GB to zstd Parquet in your browser and flattens nested objects up to 8 levels deep, free with no signup. Drop the file and choose Parquet in the Export menu; to keep the nesting, use DuckDB or pandas.
No file handy? Open Every country, as nested JSON (250 rows, 1.4 MB).
Convert JSON or JSONL to Parquet in rows.page
rows.page opens .json, .jsonl and .ndjson files. DuckDB-WASM reads the file inside your browser tab, so nothing is uploaded unless you press Share.
- Drop the file on rows.page, choose it from disk, or click Paste data and paste the JSON.
- Check the grid: nested objects show up as dot-path columns like
user.address.city, and arrays stay list columns that show the first 6 items and "+N". - Filter rows, hide columns or run SQL in the search box above the grid if you only need part of the data.
- Open the Export menu and choose Parquet. rows.page writes the file with zstd compression.
The export follows your current view: hidden columns are left out and a filtered view writes every matching row. A SQL result exports up to 1,000,000 rows.
How nested JSON maps to Parquet columns
The Parquet file from rows.page is flat. Each nested field becomes its own column named by its path, dots included, and the export writes those columns as they are:
{"user": {"address": {"city": "Utrecht"}}}becomes one column nameduser.address.city."tags": ["sql", "json"]stays a single list column and exports as a Parquet list, objects inside the list included.- Nesting below 8 levels, or an object with more than 200 fields, stays whole as one struct column.
- A text column holding JSON objects is expanded into dot-path columns when 90% or more of its first 1,000 non-empty values are valid JSON objects.
- A file that is one object wrapping a list, such as
{"data": [...]}, opens as the rows of its biggest list (searched up to 4 levels deep), and a note says the other top-level fields were skipped.
Rename, cast or explode fields with SQL before exporting
Type a statement that starts with SELECT, WITH or FROM into the search box; the table is called data. Put dot-path names in double quotes, because DuckDB reads an unquoted user.address.city as a table called user and stops with an error.
SELECT
id,
"user.address.city" AS city,
CAST("order.total" AS DOUBLE) AS total,
unnest(tags) AS tag
FROM data
WHERE "order.total" IS NOT NULL
ORDER BY __ridunnest(tags) gives one row per array item, so a record with an empty tags array drops out of the result. ORDER BY __rid uses the hidden row-number column to keep the original file order. When the result looks right, export it as Parquet.
Compare JSON to Parquet conversion methods
| Method | Nested objects become | Install needed | Size limit |
|---|---|---|---|
| rows.page | Dot-path columns (8 levels, 200 fields per object); arrays stay lists | None, runs in the browser | 1.5 GB per tab |
| DuckDB | STRUCT columns; arrays become LIST columns | duckdb CLI or Python package | Your disk and memory |
| pandas | STRUCT columns; arrays become lists | pandas and pyarrow | Your RAM; the whole file loads at once |
Pick rows.page when a flat table is what you want. Use DuckDB or pandas when the Parquet file must keep its nested structure, or when the file is bigger than 1.5 GB: rows.page refuses a larger .json file and opens only the first rows of a larger JSONL file.
Convert JSON to Parquet with DuckDB or pandas
DuckDB
read_json reads both JSON arrays and JSONL, and COPY writes the Parquet file. Nested objects stay STRUCT columns and arrays stay LIST columns.
COPY (SELECT * FROM read_json('in.json')) TO 'out.parquet' (FORMAT parquet, COMPRESSION zstd);A glob such as read_json('logs/*.jsonl') combines many files into one Parquet file.
pandas
pandas writes Parquet through pyarrow, so install both. Pass lines=True for JSONL and leave it out for a JSON array; nested objects become STRUCT columns here too.
import pandas as pd
pd.read_json('in.jsonl', lines=True).to_parquet('out.parquet')Check the Parquet file
Drop out.parquet back onto rows.page to check it. Parquet is not held to the 1.5 GB check because DuckDB reads it in place, and rows load in pages of 100 as you scroll.
The Columns panel shows each column's type, number of distinct values and share of nulls, plus a histogram with the value range for numbers and dates. For averages and medians, run FROM (SUMMARIZE data) in the search box. In DuckDB, DESCRIBE SELECT * FROM 'out.parquet' lists the columns and their types.
rows.page limits and prices
| What | Limit or price |
|---|---|
| Open a file in your browser | Files up to 1.5 GB, $0, no account, nothing uploaded |
| Share a link without an account | $0, files up to 100 MB, link deleted 7 days after creation |
| Free account | $0, 10 datasets kept, last 3 versions |
| Pro | $12/month, 100 datasets, files up to 500 MB, private links |
| Max | $39/month, 1,000 datasets, files up to 2 GB, private links |
Questions
Why are my nested fields flat in the Parquet file?
rows.page flattens nested objects into dot-path columns such as user.address.city, up to 8 levels deep and 200 fields per object, and the Parquet export writes those columns as they are. To keep STRUCT columns, convert with DuckDB's COPY command instead.
How big a JSON file can I convert in the browser?
Up to 1.5 GB per tab. A bigger .json file is refused with "Too big for this browser", and a JSONL file over 1.5 GB opens only its first rows, so convert those with DuckDB.
Is my JSON uploaded during the conversion?
No. DuckDB-WASM reads the file and writes the Parquet export inside your browser, and nothing is uploaded unless you press Share.
How do I drop duplicate records before exporting?
Run SELECT DISTINCT * EXCLUDE (__rid) FROM data in the search box and export the result as Parquet. Leaving out the hidden __rid row number lets identical records match; SQL results export up to 1,000,000 rows.
Can I convert a JSON file from a URL?
Yes. Put the public URL after rows.page/, as in https://rows.page/https://example.com/data.json, then export as Parquet. If the host blocks cross-origin requests, rows.page fetches the file through its proxy (up to 100 MB, 30 seconds, 5 redirects).