Split a CSV file
How to split a large CSV file into smaller files
rows.page splits a CSV of up to 1.5 GB in your browser: export chunks of up to 1,000,000 rows with SQL, or filter by a column value and export every matching row. It's free with no signup, and the file stays on your computer.
No file handy? Open CO2 emissions by country and year (50k rows, 14 MB).
Why split a large CSV file
An Excel worksheet holds 1,048,576 rows. Open a bigger CSV and Excel loads only that many, warning "This data set is too large for the Excel grid. If you save this workbook, you'll lose data that wasn't loaded." Upload tools have caps too: ChatGPT takes CSV and spreadsheet files up to about 50 MB.
| Method | Splits by | Header in every file | Limit |
|---|---|---|---|
rows.page SQL (LIMIT and OFFSET) | Row count | Yes | Files up to 1.5 GB; 1,000,000 rows per query |
rows.page filter (country:NL) | Column value | Yes | Files up to 1.5 GB; every matching row |
GNU split -l | Line count | First file only | Runs on disk |
head, tail and split loop | Line count | Yes | Runs on disk |
DuckDB PARTITION_BY | Every value of a column at once | Yes | Runs on disk |
Split a CSV by row count in rows.page
Each chunk is one SQL query. Ordering by the hidden __rid column, the row number from the file, keeps the original order:
SELECT * FROM data ORDER BY __rid LIMIT 500000 OFFSET 0- Open
https://rows.pageand drop your CSV or TSV file on the page. - Type the query above in the search box and press Enter.
- Open the Export menu and choose CSV to download the first chunk.
- Raise the offset by 500,000 (
OFFSET 500000, thenOFFSET 1000000) and export again until a query returns fewer than 500,000 rows.
SQL results stop at 1,000,000 rows, so keep LIMIT at 1000000 or below. Every CSV export has the header row, commas and UTF-8 without a BOM, and the __rid column is left out. Text cells that start with =, +, - or @ get a leading apostrophe so spreadsheets don't run them as formulas.
Split a CSV by column value in rows.page
To pull out the rows for one country, status or customer, use a filter instead of SQL. A filtered view exports every matching row, even past 1,000,000, with only the columns you have visible.
- Drop your file on
https://rows.page. - Type a filter in the search box, such as
country:NL,country:NL OR country:BEorcountry:NL price:>20, or click a top value or histogram bar in the Columns panel. - Hide any columns you don't want in the output.
- Open the Export menu and choose CSV, Parquet, JSON or JSONL.
To hand the subset to someone, click Share. It uploads the whole file, and the link opens with your filter applied, so the other person can still clear it and see every row.
Split a CSV of any size on the command line
GNU split
For files over 1.5 GB, or to write every chunk in one go, use split. It treats the CSV as plain lines, so the header ends up in the first file only:
split -l 500000 big.csv part_That writes part_aa, part_ab and so on, 500,000 lines each. Because split counts line breaks, not CSV records, a quoted field with a line break inside it can be cut in half.
Keep the header in every part
Save the header, split the rest, then put the header back on each part with a .csv extension:
head -n 1 big.csv > header.csv
tail -n +2 big.csv | split -l 500000 - part_
for f in part_*; do cat header.csv "$f" > "$f.csv" && rm "$f"; doneDuckDB: one file per value
To write a separate file for every value in a column, run PARTITION_BY in the DuckDB command-line tool. DuckDB parses the CSV properly, including line breaks inside quoted fields:
COPY (SELECT * FROM 'big.csv') TO 'out' (FORMAT csv, HEADER, PARTITION_BY (country), WRITE_PARTITION_COLUMNS true);You get one folder per value, such as out/country=NL/data_0.csv, each file with its own header. Without WRITE_PARTITION_COLUMNS true, DuckDB leaves the country column out of the files and keeps it only in the folder name.
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
How do I split a CSV that is too big for Excel?
Excel worksheets hold 1,048,576 rows. Open the CSV in rows.page, run SELECT * FROM data ORDER BY __rid LIMIT 500000 OFFSET 0, export it as CSV, and repeat with OFFSET 500000, OFFSET 1000000 and so on. Each file gets its own header row.
How do I keep the header row in every split file?
Every CSV export from rows.page includes the header row. On the command line, run head -n 1 big.csv > header.csv, then tail -n +2 big.csv | split -l 500000 - part_, then for f in part_*; do cat header.csv "$f" > "$f.csv" && rm "$f"; done.
Why did my SQL export stop at 1,000,000 rows?
SQL results in rows.page stop at 1,000,000 rows. Keep LIMIT at 1000000 or below when you split by row count, or use a filter such as country:NL, which exports every matching row.
Can rows.page split a 2 GB CSV file?
Not in full. rows.page holds 1.5 GB per browser tab, so a 2 GB CSV loads partially with the note "Loaded the first N rows: the file is X, more than the browser can hold." Split it with split -l or DuckDB PARTITION_BY, or convert it to Parquet with the DuckDB command line, since rows.page doesn't hold Parquet to the 1.5 GB check.
Does rows.page upload my CSV when I split it?
No. Opening, filtering, running SQL and exporting all happen in your browser with DuckDB-WASM. Nothing is uploaded unless you click Share or push the file with curl -T data.csv https://rows.page.