JSON to Excel
How to convert JSON to Excel, nested JSON included
rows.page flattens nested JSON up to 8 levels deep into a CSV that Excel opens, free with no signup, up to Excel's 1,048,576-row sheet limit. It doesn't write .xlsx, so you save the workbook in Excel. Excel's From JSON connector and pandas are the other routes, and they hit the same limit.
No file handy? Open Every country, as nested JSON (250 rows, 1.4 MB).
Three ways to get JSON into Excel
Pick a route by how deeply nested your records are and whether you write code. Excel can read a JSON file itself, rows.page flattens it in your browser and exports CSV, and pandas writes .xlsx from a script.
| Route | Nested JSON | Row limit | Cost |
|---|---|---|---|
| Excel Power Query (From JSON) | Detects the table; you expand Record and List columns by hand | 1,048,576 rows per sheet | Included with Excel |
| rows.page, then Excel From Text/CSV | Flattens objects up to 8 levels and 200 child fields; lists export as JSON text | No limit in rows.page; 1,048,576 rows in Excel | Free, no signup |
| pandas with openpyxl | pd.json_normalize flattens objects; lists stay as text | 1,048,576 rows per sheet | Free, open source |
Open JSON in Excel with Power Query
Excel has a JSON connector in Microsoft 365 on Windows and Mac. Power Query detects the table in the file and flattens what it can.
- In Excel, choose Data > Get Data > From File > From JSON.
- Pick the
.jsonfile and select Open. The Power Query Editor opens with the detected table. - If a column still shows Record or List, click the expand button in its header to pick fields or turn list items into rows.
- Select Close & Load to put the table on a worksheet.
The connector doesn't read JSON Lines as is; Microsoft's workaround is M code with Lines.FromBinary and Json.Document. For JSONL files, or JSON with many nested levels, flatten the file in rows.page first.
Convert JSON to Excel with rows.page
rows.page opens .json, .jsonl, .ndjson and .ldjson files in your browser with DuckDB-WASM, or raw JSON you paste with Paste data. Nothing is uploaded unless you press Share.
- Drop the file on rows.page. A
.jsonfile can be up to 1.5 GB per browser tab; a bigger JSONL file loads its first rows. - Check the columns: nested objects become dot-path columns such as
user.address.city, and a wrapper like{"data": [...]}is unwrapped to its biggest list. - Hide fields you don't need in the Columns panel, or narrow the rows with the filter box.
- Choose Export > CSV.
- In Excel, choose Data > Get Data > From File > From Text/CSV, pick the CSV, set File Origin to 65001: Unicode (UTF-8) and select Load. Then use File > Save As to save the workbook as
.xlsx.
The File Origin step matters because Excel only assumes UTF-8 when a CSV starts with a byte order mark (BOM), and rows.page exports UTF-8 without one. Double-clicking the CSV instead can turn é into é. Text cells that start with =, +, - or @ get a leading apostrophe so Excel doesn't run them as formulas.
Arrays, row limits and trimming before export
Arrays inside a record stay as list columns: the grid shows the first 6 items and +N, and the CSV export writes each list as JSON text in one cell. For one row per array item, run SQL in the filter box, with double quotes around column names that contain dots:
SELECT
id,
"user.address.city" AS city,
unnest(tags) AS tag
FROM dataRows whose list is empty drop out of an unnest result. A SQL result shows and exports up to 1,000,000 rows, which fits in one Excel sheet.
An Excel sheet holds 1,048,576 rows by 16,384 columns, while the rows.page grid has no row limit. A filtered view exports every matching row, so narrow a big file below that limit first: filter with country:NL, price:>20, name:* (has a value) or -name:* (is empty), or click a histogram bar or top value in the Columns panel.
Convert JSON to .xlsx in Python with pandas
pandas writes .xlsx files directly through openpyxl (pip install pandas openpyxl), with no CSV step:
import json
import pandas as pd
with open("input.json", "r", encoding="utf-8") as f:
records = json.load(f)
pd.json_normalize(records).to_excel("out.xlsx", index=False)pd.json_normalize joins nested keys with dots, like user.address.city in rows.page; pass record_path when the records sit under a wrapper key. Lists are written as Python text such as ['a', 'b'], not JSON. to_excel raises an error when the DataFrame has more than 1,048,576 rows or 16,384 columns.
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
Does rows.page upload my JSON file to a server?
No. rows.page reads the file inside your browser with DuckDB-WASM. Nothing is uploaded unless you press Share ("Upload and get a link") or push the file from a terminal with curl -T.
Why do accents look broken when I double-click the exported CSV in Excel?
rows.page exports CSV as UTF-8 without a BOM, and Excel only assumes UTF-8 when the file starts with one. Open the file with Data > Get Data > From File > From Text/CSV and set File Origin to 65001: Unicode (UTF-8) instead.
How big a JSON file can rows.page open?
A .json file up to 1.5 GB per browser tab; a larger one is refused with "Too big for this browser". A JSONL file over 1.5 GB loads its first rows with a note instead. Excel still stops at 1,048,576 rows per sheet.
What if my JSON is a single object like {"data": [...]} instead of an array?
rows.page unwraps a single top-level object to its biggest list, up to 4 levels deep, and loads the items as rows with the note: Showing the N items in "data"; the other top-level fields were skipped.
Can I open a JSON file from a public URL without downloading it?
Yes. Put the URL after https://rows.page/, for example https://rows.page/https://example.com/data.json; raw GitHub, Hugging Face /resolve/ and S3 presigned links work. If the host blocks cross-origin requests, rows.page fetches the file through its proxy (up to 100 MB, 30 seconds, 5 redirects) and stores nothing.