"Large" is not a fixed number. What matters is the relationship between the file on disk and the memory needed to hold it as parsed objects — and those two figures are further apart than most people expect.
Why a 100 MB file needs far more than 100 MB of RAM
When you call JSON.parse() or json.load(), the text is turned into in-memory objects. Each object carries overhead the text file does not: type tags, hash tables for keys, pointers, alignment padding.
A rough rule from experience: expect parsed JSON to occupy 6 to 10 times the file size in memory. Records with many short keys sit at the worse end, because every key string and every object header is paid for on every single row.
| File on disk | Rough memory when parsed | Practical outlook |
|---|---|---|
| 1 MB | 6–10 MB | Instant everywhere |
| 10 MB | 60–100 MB | Fine in a browser |
| 50 MB | 300–500 MB | Browser struggles; desktop tools fine |
| 200 MB | 1.2–2 GB | Needs streaming or a 64-bit process |
| 1 GB+ | 6–10 GB | Streaming only |
This is why browser-based converters, including ours, publish a file-size limit. It is not an arbitrary restriction — a browser tab typically gets between 1 and 4 GB of address space, and it also has to hold the generated spreadsheet at the same time. Our converter is capped at 10 MB because that is the size at which conversion stays comfortably instant on ordinary hardware, including phones.
The Excel ceiling, which arrives sooner than you think
Before optimising anything, check whether the destination can hold the data at all. An .xlsx worksheet is limited to:
- 1,048,576 rows
- 16,384 columns (column XFD)
- 32,767 characters in a single cell
A 500 MB JSON file of typical API records is often several million rows. No amount of clever conversion puts that on one sheet. If you are past a million rows, the honest answer is that Excel is the wrong destination — you want a database, Parquet, or CSV feeding a BI tool.
Ask what the spreadsheet is for. In practice, most people asking to convert a huge JSON file do not need every row — they need a filtered subset, or a summary. Reducing the data before conversion is nearly always faster and more useful than converting everything and filtering afterwards.
Step one: find out what is actually in the file
Do not open it in a text editor. Editors load the whole file and build syntax-highlighting structures on top, which is how a 200 MB file freezes a machine with 16 GB of RAM.
Read the first few hundred bytes instead:
# macOS / Linux
head -c 500 big.json
# Windows PowerShell
Get-Content big.json -TotalCount 1 | ForEach-Object { $_.Substring(0, 500) }That tells you the shape — whether the root is an array or an object, and what the fields are. Then count the records without parsing:
# if the file is JSON Lines, one object per line
wc -l big.jsonStreaming: parse without loading everything
A streaming parser reads the file in chunks and emits each record as it is encountered, so memory use stays flat regardless of file size.
Python with ijson
pip install ijson openpyxlimport ijson
from openpyxl import Workbook
wb = Workbook(write_only=True)
ws = wb.create_sheet("Data")
headers = None
with open("big.json", "rb") as f:
# "item" yields each element of the root array in turn
for record in ijson.items(f, "item"):
if headers is None:
headers = list(record.keys())
ws.append(headers)
ws.append([record.get(h) for h in headers])
wb.save("output.xlsx") Two details make this work at scale. ijson.items(f, "item") never holds more than one record at a time. And Workbook(write_only=True) tells openpyxl to stream rows to disk instead of building the whole sheet in memory — without it, you have simply moved the memory problem from parsing to writing.
The headers-from-first-record approach assumes consistent keys. If later records have fields the first one lacks, those columns are silently dropped. If your data is ragged, do a first pass collecting the union of all keys, then a second pass writing rows.
Node.js with stream-json
npm install stream-jsonconst fs = require('fs');
const { parser } = require('stream-json');
const { streamArray } = require('stream-json/streamers/StreamArray');
let count = 0;
fs.createReadStream('big.json')
.pipe(parser())
.pipe(streamArray())
.on('data', ({ value }) => {
count++;
// process one record at a time
})
.on('end', () => console.log(`processed ${count} records`));Splitting a large file into manageable pieces
If you would rather keep using familiar tools, split the file first and convert each piece:
import ijson, json
CHUNK = 50_000
chunk, part = [], 1
with open("big.json", "rb") as f:
for record in ijson.items(f, "item"):
chunk.append(record)
if len(chunk) == CHUNK:
with open(f"part_{part}.json", "w", encoding="utf-8") as out:
json.dump(chunk, out)
chunk, part = [], part + 1
if chunk:
with open(f"part_{part}.json", "w", encoding="utf-8") as out:
json.dump(chunk, out) Each part_N.json is small enough for any converter, including browser-based ones. This is often the pragmatic answer: one streaming script you run once, then normal tools.
Filtering before converting
Usually the fastest fix is to convert less. jq is built for this and streams by default:
# keep only the fields you need
jq '[.[] | {id, name, email}]' big.json > small.json
# keep only rows matching a condition
jq '[.[] | select(.status == "active")]' big.json > active.json
# pull out a nested array as the new root
jq '.results' wrapped.json > results.jsonDropping from forty fields to five typically cuts the file by 80 percent or more, and the result often falls under a converter's limit without any further work.
Convert to CSV instead
CSV has no row limit, streams naturally, and every analysis tool reads it. If the destination is really a database, a BI tool, or pandas, going through .xlsx adds cost for no benefit.
import ijson, csv
with open("big.json", "rb") as fin, \
open("out.csv", "w", newline="", encoding="utf-8") as fout:
writer = None
for record in ijson.items(fin, "item"):
if writer is None:
writer = csv.DictWriter(fout, fieldnames=list(record.keys()))
writer.writeheader()
writer.writerow(record)The trade-offs between the formats are covered in JSON vs CSV vs Excel.
Choosing an approach
| Situation | Do this |
|---|---|
| Under 10 MB | Any converter, including in-browser |
| 10–50 MB, one-off | Python with pandas, or split into chunks |
| 50 MB+, need all rows | Stream with ijson or stream-json |
| Only need some fields | Filter with jq first, then convert |
| Over ~1M rows | CSV or a database — Excel cannot hold it |
| One object per line | See JSONL to Excel |
A note on validating large files
Online validators load the whole document, so they fail on exactly the files you most want to check. Validate from the command line instead:
# exits non-zero and prints the location of the first error
jq empty big.json
# Python equivalent
python -c "import json,sys; json.load(open(sys.argv[1], encoding='utf-8'))" big.jsonBoth still parse the whole file, but they do it without a UI and without syntax highlighting, which is where editors spend most of their memory. For the errors these will report, see common JSON errors and how to fix them.
File under 10 MB?
Convert it instantly in your browser — nested objects flattened automatically, nothing uploaded to a server.
Convert JSON to Excel Now →