Query JSON with SQL
How to query a JSON file with SQL, no database needed
rows.page runs SQL on JSON or JSONL files up to 1.5 GB, with results up to 1,000,000 rows, free with no signup. Type a query against the table data; DuckDB-WASM runs it inside your browser, so the file is not uploaded unless you click Share.
No file handy? Open Every country, as nested JSON (250 rows, 1.4 MB).
How to query a JSON file with SQL in rows.page
Drop a .json, .jsonl, .ndjson or .ldjson file onto rows.page, or click Paste data to paste JSON or JSONL from your clipboard. A single top-level object such as {"data": [...]} is unwrapped to its biggest list, up to 4 levels deep, and a note says the other top-level fields were skipped.
- Open the file. Rows load in pages of 100 as you scroll.
- Type a query into the filter box above the grid, such as
SELECT * FROM data WHERE price > 20. The table is alwaysdata, and the statement must start withSELECT,WITHorFROM. - Press Enter to run it; Shift+Enter adds a line break. Results show up to 1,000,000 rows, marked
first 1Mwhen the cap is hit.
| Task | SQL to type in rows.page |
|---|---|
| Filter rows | SELECT * FROM data WHERE status = 'paid' AND amount > 50 |
| Group and count | SELECT status, count(*) AS n FROM data GROUP BY status ORDER BY n DESC |
| Query a nested field | SELECT "user.address.city", count(*) FROM data GROUP BY 1 |
| Explode an array column | SELECT id, unnest(tags) AS tag FROM data |
| Latest row per key | SELECT * FROM data QUALIFY row_number() OVER (PARTITION BY user_id ORDER BY created_at DESC) = 1 |
| Profile all columns | FROM (SUMMARIZE SELECT * EXCLUDE (__rid) FROM data) |
| De-duplicate all columns | SELECT DISTINCT * EXCLUDE (__rid) FROM data |
The data table also has a hidden __rid column with the row number. ORDER BY __rid keeps the file order, and SELECT * results hide it, but SELECT DISTINCT * and SUMMARIZE still include it unless you write * EXCLUDE (__rid). SELECT DISTINCT does not keep the original row order.
How to query nested JSON objects and arrays
rows.page flattens nested objects into dot-path columns such as user.address.city, up to 8 levels deep and 200 child fields per object. A text column holding JSON is expanded too when 90% or more of its values in the first 1,000 rows are JSON objects. Wrap these column names in double quotes in SQL: unquoted, DuckDB reads user.address.city as a column of a table called user and fails.
Arrays stay list columns, and the grid shows their first 6 items plus +N. Call unnest() in the SELECT list to give each item its own row:
SELECT
id,
"user.address.city" AS city,
unnest(items) AS item
FROM data
WHERE "user.active" = trueTo read one record without SQL, click its row. A side drawer opens with a JSON/Fields toggle and Copy as JSON; there is no tree view of the whole file.
How to export or share a SQL result
The Export menu saves the current result:
- CSV: comma-delimited, UTF-8 without a BOM, header row. Cells starting with
=,+,-,@, a tab or a carriage return get a leading apostrophe so spreadsheets don't run them as formulas. - Parquet: zstd compression.
- JSON: one array of objects; flattened fields keep dot-path keys and lists stay arrays.
- JSONL: one object per line.
- Markdown: a table of the first 1,000 rows; nulls become empty cells,
|is escaped as\|and lists are written as JSON text.
A SQL result exports at most 1,000,000 rows; a filtered view without SQL exports every matching row.
Share uploads the file and opens it at a https://rows.page/<id> link with your query still applied; Pin the current view on the Findings tab saves the query there. One push is capped at 100 MB on every plan, and a JSON or JSONL file over 16 MB is converted to Parquet in your browser first when that makes it at least 20% smaller. Pro ($12 per month) and Max ($39 per month) accept files up to 500 MB and 2 GB, but only through the API's multipart uploads. The link expires after 7 days unless you press Keep it on the dataset page.
How to query JSON files over 1.5 GB with the DuckDB CLI
rows.page refuses a .json file over 1.5 GB ("Too big for this browser") and loads only the first rows of a bigger JSONL file. It also cannot join two files. For either case, install the DuckDB CLI and query the file from your terminal:
SELECT
user.address.city AS city,
count(*) AS total
FROM read_json('file.json')
GROUP BY city
ORDER BY total DESC;read_json detects both JSON arrays and newline-delimited JSON. Nested objects stay STRUCT columns instead of being flattened, so user.address.city works without double quotes.
How to query JSON columns in Postgres and SQLite
If the JSON already sits in a database column, query it there. In Postgres, -> returns json or jsonb, so you can chain another key, and ->> returns text for filtering and sorting:
SELECT
payload -> 'user' ->> 'city' AS city,
count(*)
FROM events
WHERE payload ->> 'status' = 'active'
GROUP BY 1;In SQLite, json_extract(col, '$.a.b') reads a value from a JSON text column by path:
SELECT
json_extract(payload, '$.user.city') AS city,
count(*)
FROM events
WHERE json_extract(payload, '$.status') = 'active'
GROUP BY 1;Which tool to use for SQL on JSON
- rows.page: a JSON or JSONL file up to 1.5 GB, or a public file URL, when you want SQL without installing anything, plus flattened nested fields, column histograms and export to CSV, JSON, JSONL, Parquet or Markdown.
- DuckDB CLI: a JSON or JSONL file over 1.5 GB, results over 1,000,000 rows, or a
JOINacross files. - Postgres or SQLite: the records already live in a database table.
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
Can I run UPDATE or CREATE TABLE on a JSON file in rows.page?
No. The SQL box runs one statement that starts with SELECT, WITH or FROM, and cells can't be edited. Transform values in the SELECT list instead and export the result as CSV, JSON, JSONL, Parquet or Markdown.
Why does my SQL query fail on a nested JSON column name?
rows.page flattens nested objects into column names that contain dots, such as user.address.city. Without quotes, SQL treats each dot as a table or field separator, so write "user.address.city" in double quotes.
Can I query a JSON file hosted at a URL without downloading it first?
Yes. Put the public file URL after https://rows.page/, such as https://rows.page/https://example.com/data.json. Your browser fetches it directly, or rows.page proxies it when the host blocks cross-origin requests (up to 100 MB, 30 seconds and 5 redirects), and nothing is stored unless you click Save to rows.page.
How do I calculate average, median or standard deviation on a JSON field?
The Columns panel shows min, max, distinct counts and histograms, but no mean, median or standard deviation. Type SELECT avg(price), median(price), stddev(price) FROM data, or FROM (SUMMARIZE SELECT * EXCLUDE (__rid) FROM data) for avg, std and quartiles of every column.
Can I join two JSON files with SQL in rows.page?
No. rows.page queries one file at a time as the table data and can't join or merge files. Use the DuckDB CLI instead and join read_json('first.json') with read_json('second.json').