Skip to main content
L
Loopaloo
Buy Us a Coffee
All ToolsImage ProcessingAudio ProcessingVideo ProcessingDocument & TextPDF ToolsCSV & Data AnalysisConverters & EncodersWeb ToolsMath & ScienceGames
Guides & BlogAboutContact
Buy Us a Coffee
L
Loopaloo

Free online tools for developers, designers, and content creators. Your files are processed in your browser and are never uploaded - no accounts required. A few network utilities (like What's My IP and Currency Converter) call public APIs to do their job and say so on their pages.

support@loopaloo.com

Tool Categories

  • Image Tools
  • Audio Tools
  • Video Tools
  • Document & Text
  • PDF Tools
  • CSV & Data
  • Converters
  • Web Tools
  • Math & Science
  • Games

Company

  • About Us
  • Contact
  • Blog
  • FAQ

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

Support

Buy Us a Coffee

© 2026 Loopaloo. All rights reserved. Built with privacy in mind.

Privacy|Terms|Disclaimer
  1. Home
  2. CSV & Data Analysis
  3. CSV Splitter
Add to favorites

CSV Splitter

Split a CSV by rows, file count, column value or a real byte-size maximum, with every input row accounted for exactly once

Rows never leave your deviceMore csv & data analysisJump to full guide

Initializing in your browser…

You might also like

CSV Viewer & Editor

View, sort and edit a CSV, with an undo stack that goes back exactly one step and a parse report that tells a broken quote from a ragged row

CSV to JSON Converter

Convert both ways, converting a type only when it reads back the same, and naming every value that cannot

CSV Formatter & Validator

Format and validate against RFC 4180 by section, with output verified by reading it back

A sample run

A 600 row file whose short rows come first and long rows last, split into files of at most 20 KB. And a twelve row file grouped by a region column holding A-B, A_B, A B, an empty value, the word empty, and cafe with an accent.

Two splits

1. By maximum size: 20 KB, on 300 rows of 5 characters followed by 300 of 400
2. By column value: region, on 12 rows across 6 distinct values
What CSV Splitter produces

Result

By size: 7 files of 20,254  20,312  20,312  20,312  20,312  20,312  3,260 bytes
         largest 20,312 against a 20,480 byte limit; 600 rows in, 600 out

By column: 6 files
  sales_A-B.csv          2 rows   sales_A_B.csv     2 rows
  sales_A B.csv          2 rows   sales_empty.csv   2 rows
  sales_empty-value.csv  2 rows   sales_café.csv    2 rows
  12 rows in, 12 out

Both of these were wrong before, and both were wrong silently. The size estimate averaged the first 100 rows, which on this file are the short ones: 8.9 characters each, giving 2,301 rows per file and therefore ONE file, holding everything, when 20 KB was asked for. Sizes are the real encoded byte length now, so the limit is a limit. And the six group values used to collapse to four file names, because everything outside A to Z, a to z and 0 to 9 became an underscore: A-B, A_B and A B were one file, the empty value merged with the word empty, and cafe with an accent became caf_. A zip holds one entry per name, so the losing groups were gone from the download with nothing said. Both splits now show the rows that went in beside the rows that came out.

Splitting Where the Sizes Are Real Byte Counts

Split a CSV into smaller files by row count, file count, column value or maximum size. The sizes are the real encoded byte length of what will be written rather than an estimate, and the tool shows that every input row ended up in exactly one output file.

How to use

  1. 1Upload your CSV file, or load the 2,500 row sample
  2. 2Choose how to split: by rows, by file count, by column value, or by maximum size
  3. 3Set the number or pick the grouping column
  4. 4Check the file list: every part shows its real byte size and row count
  5. 5Check that the data rows out equal the data rows in, then download the zip

Key features

  • Sizes that are the real encoded UTF-8 byte length, verified against the downloaded archive to the byte
  • A maximum file size rather than an estimate: no file exceeds it unless one row does not fit alone
  • A row that is larger than the limit on its own is reported rather than silently oversizing a file
  • A partition check on every split: data rows out shown against data rows in
  • File names that keep accents, spaces, hyphens and non-Latin characters
  • Two files that would share a name get a numbered suffix, with the rename reported
  • An empty value in the grouping column kept apart from a value that is literally the word empty
  • Asking for more files than there are rows writes as many as there are, and says so
  • Zero-padded part numbers by default, so the files sort correctly in a listing
  • The header repeated in every file, or written once, as you choose
  • RFC 4180 output: CRLF records, minimum quoting, and a UTF-8 byte order mark
  • Single-column CSV files load, instead of being refused as undelimited
  • 200,000 rows packed in about 70 milliseconds

How it works

Measured on 2026-09-02 by downloading the archive and opening it with Python's zipfile, which is the only reference that settles the question: a "500 KB" file that is 380 KB is wrong by a number the file system already knows.

Splitting by size was an estimate, and the estimate was wrong in four independent ways. A row's size was taken as row.join(',').length + 1, averaged over the FIRST 100 ROWS ONLY. Measured on four files at a 100 KB target, the parts came out between 5.2 KB and 284.7 KB, and a 1.2 MB file whose long rows came last was written as ONE file of 1,226.5 KB, twelve times what was asked for. The four faults: String.length counts UTF-16 code units and a file is measured in bytes, so a column of CJK text was estimated at a third of its size; row.join(',') is not the CSV encoding of a row, since RFC 4180 section 2.6 quotes a field holding a comma or a quote and section 2.7 doubles each inner quote; a mean over the first 100 rows describes the first 100 rows; and neither the repeated header nor the two-byte CRLF separator was counted at all. Nothing here is estimated now. Each row's encoded length is computed once, the files are packed against those numbers, and across eight runs every predicted size equalled the file that was written, to the byte. The setting is a MAXIMUM rather than a target: no file exceeds it unless a single row is larger than the limit on its own, which is reported, because a row cannot be cut in half.

Splitting by column value lost rows. Group values were turned into file names by replacing every character outside A to Z, a to z and 0 to 9 with an underscore, so A-B, A_B and A B all became the same name, and a zip archive holds one entry per name: on a ten row file, four rows silently vanished and the download said nothing. Every non-Latin name collapsed the same way, cafe with an accent becoming caf_ and two different Japanese city names both becoming three underscores. File names keep their characters now, only what a file system actually refuses is replaced, and two files that would still share a name get a numbered suffix with the rename reported. The same ten row file now produces nine files holding all ten rows.

An empty value in the grouping column was turned into the literal string "empty", which merged it with rows whose value really is the word empty. The empty group is a flag now rather than a placeholder string, the same answer the pivot table gives, and the two stay apart.

Asking for more files than there are rows produced files with nothing in them: five files from a two row table gave three holding a header and no data. It writes as many files as there are rows and says why.

Every split now carries a partition check, the same one the merger, the comparator and the missing-data analyzer carry: the data rows across every output file are counted and shown against the data rows that went in. If those two numbers ever differ, the page says so rather than letting an archive quietly hold less than the file did.

Output files are written by RFC 4180: CRLF records per section 2.1, quoting as a minimum rather than a preference, and a UTF-8 byte order mark so a spreadsheet reads them correctly. The default naming pattern zero pads the part number, so part01 through part12 sort into the right order in a file listing. And a single-column CSV loads, where it used to be refused outright because papaparse reports UndetectableDelimiter for a file with no delimiter in it to detect.

Where this fits a data pipeline

  • Getting under an upload or attachment limit

    Set the maximum to whatever the limit is and every file is under it, because the size is measured rather than estimated. The previous version could produce a file twelve times the number you typed.

  • Bypassing spreadsheet row limits

    Break a million-row export into chunks a spreadsheet can open, with the header repeated in each one.

  • Segmenting data by category

    One file per region, department or customer, with the file names keeping the values as they are written rather than flattening them into underscores.

  • Checking nothing was lost

    The rows-in and rows-out counts sit next to each other above the file list, so a split that dropped something is visible before you download it.

Frequently asked questions

Is the size setting a target or a maximum?

A maximum. Files are packed against the real encoded byte length, so none exceeds the number you type. The single exception is a row that is larger than the limit on its own: it goes in a file of its own, that file is over the limit, and the page says so, because a row cannot be split in half.

Why are the file sizes different from each other?

Because rows are different lengths and a row cannot be divided. Each file takes as many rows as fit under the limit, so the last one is usually shorter and any file can end early if the next row is long.

Does each chunk include the header row?

By default yes, in every file. You can turn that off, in which case the header is written in the first file only, so the set of files holds it exactly once.

What happens if two group values would produce the same file name?

The second gets a numbered suffix and the rename is listed above the file list. Nothing is dropped. That case used to lose the rows outright: A-B, A_B and A B all became one file and only one of the three groups survived.

What happens to rows with an empty value in the grouping column?

They go into their own file, kept apart from rows whose value is literally the word "empty". A row too short to have that column at all is grouped with the empty value and counted in a note.

Can I ask for more files than I have rows?

You can ask, and you get one file per row rather than a set padded out with files holding nothing but a header. The page says how many were written and why.

How do I know nothing was lost?

The preview shows the data rows that went in and the data rows across every output file side by side. They should be equal, and the tool flags it in red if they are not.

What format are the output files?

CSV by RFC 4180: CRLF record separators, fields quoted where section 2.6 requires it, and a UTF-8 byte order mark so a spreadsheet reads accented and non-Latin text correctly. They are packaged in a single zip.

Private by design

Rows and columns are parsed and transformed in memory in your browser. No record ever reaches a server.