Split PDF
Split a PDF into multiple files by page range, every N pages, or one PDF per page — fully inside your browser, no signup, no upload. Each output keeps the original pages byte-identical; nothing is re-rasterised. Sources cited.
How it works
A PDF file is, in spec terms, a body of numbered objects (pages, fonts, images, content streams) plus a cross-reference table that tells a reader the byte offset of each object. The page tree (ISO 32000-2 §7.7.3.2) is a shallow structure: a root /Pages dictionary points to /Kids (each a /Page object), and the catalog points to that root. To split a PDF you copy a subset of the page objects — together with everything they reference (fonts, images, resources, content streams) — into a fresh document and rebuild a single page-tree root over the lot. That is what this tool does for every output range.
The split is performed by pdf-lib, an MIT-licensed pure-JavaScript PDF library. It is loaded dynamically when you press Split — until then the page bundle stays small and your browser does not download the ~270 KB library. Inside the React component the flow is straight: PDFDocument.load(bytes) for the source, then for each output range a fresh PDFDocument.create() plus copyPages(src, [i..j]).addPage(...), and finally save() to serialise each output.
Before any pdf-lib work runs the tool does four deterministic things so the plan can be validated up front:
- Validate the source. Confirms the PDF MIME type, a non-zero size, and a per-file cap of 100.0 MB. The first 1 KB is scanned for the literal
%PDF-n.mheader (ISO 32000-2 §7.5.2), and the last 2 KB for the%%EOFterminator (§7.5.5). Files missing either are rejected with an explanation. - Read the exact page count. pdf-lib parses the catalog and page tree and reports
getPageCount(). That number is the ceiling for every range the user enters — an out-of-bounds range becomes an inline error before the split runs. - Build a plan. The selected mode produces a list of output ranges. By-range mode parses the text expression; every-N mode walks
for (start = 1; start ≤ total; start += N); each-page mode produces N ranges of one page each. Plans are capped at 500 output files. - Cross-check the plan. The plan is summed two ways. First by arithmetic (
end − start + 1, totalled), then by independent enumeration (a nested loop that adds 1 per page visited). The two totals must agree and every page must lie inside the source. If anything is off, the Split button is disabled with a specific error. - Run the split. For each range, pdf-lib creates a destination document, copies the selected pages (preserving the original byte streams), writes a fresh catalog and trailer, and returns the merged byte buffer. Each buffer is wrapped in a Blob, exposed via an object URL, and offered to you as a download. No bytes leave the browser tab.
Choosing between the three modes
The three modes are not interchangeable, and picking the wrong one is the most common reason a split produces surprising output. Use by range when the document has meaning-bearing boundaries you already know — chapters, a single signed page, the two pages of a bank statement you actually need. It is the only mode where pages may be dropped: the outputs cover exactly the pages you name and nothing else. Use every N pages when the boundaries are regular rather than semantic — a scanned ledger where each record is four pages, or a long report you want in equal chunks small enough to email. Use each page when downstream software expects one file per page, which is the usual reason people split at all: bulk upload forms, per-page e-signing, and page-level archiving.
If what you actually want is the opposite operation — several PDFs combined into one — use the PDF Merger, which runs the same page-tree copy in reverse. If the pages come out sideways because the source was scanned in landscape, the PDF Page Rotator changes each page’s /Rotate entry without touching the content stream, so it can be run before or after a split with no quality cost either way.
Limits, caps, and version support
Three hard caps bound the work. A single source file may be up to 100.0 MB; a single split may produce at most 500 output files; and the range expression itself is capped at 4 KB of text, which is far more than any realistic comma list needs and stops a pathological paste from locking the parser. The output cap matters most in each-page mode: a 900-page scanned book would ask the browser to materialise 900 simultaneous object URLs, which every browser throttles. For jobs that large, split in two passes — first cut the source into a handful of range-based outputs, then split each of those further.
On the format side, inputs from PDF 1.4 through PDF 2.0 are accepted, which covers essentially every file produced since 2001. The version detected in the %PDF-n.m header is shown on the queued-file row, so an unusual input is easy to spot before you commit to a split. Outputs are always written as PDF 1.7, the pdf-lib default, and every reader released since 2008 reads that. Compressed cross-reference streams and object streams (§7.5.7 and §7.5.8, introduced in PDF 1.5) are handled by pdf-lib rather than by hand — that is precisely why the tool leans on a real parser instead of doing byte surgery on the file.
Edge cases the validator catches first
Range expressions are typed by hand, so most failures are typing failures. Each one is caught before pdf-lib is even loaded, and each produces a specific message rather than a generic “invalid range”:
- 5-3 — a reversed range. Rejected, because silently swapping the endpoints would hide a typo that changes which pages you get.
- 0-2 — page 0. PDF page numbers are 1-based throughout the spec and throughout this tool, so 0 is an error rather than a synonym for page 1.
- 11 on a 10-page source — out of bounds. The page count read from the catalog is the ceiling for every range, so this fails before any copying starts.
- 7-— an open-ended range. Valid, and resolves to pages 7 through the last page. This is the one case where a partial expression is deliberately accepted, because “from here to the end” is a common and unambiguous intent.
- 1-1 or 10-10 on a 10-page source — boundary cases at the first and last page. Both valid, each producing one single-page output.
- An every-N value equal to or greater than the page count — valid, and produces exactly one output containing the whole document. N = 1 is also valid and behaves identically to each-page mode.
Whatever the mode, the resulting plan is then summed twice by two independent routes: once arithmetically, as end − start + 1 totalled across ranges, and once by enumerating the plan page by page and counting visits. The two totals must agree and every page must lie inside the source. A disagreement would mean the plan builder and the page enumerator disagree about what was asked for, and in that case the Split button stays disabled rather than producing output nobody has verified.
What a split does not carry across
Each output is a genuinely new document, not a trimmed copy of the original, and that distinction decides what survives. Page-level content survives in full: text operators, vector graphics, embedded raster images, fonts, and annotations anchored to a page. Document-level structures do not, because they describe the old document rather than the new one — the outline (bookmark) tree, interactive form state held in the document’s AcroForm dictionary, document-wide JavaScript, and attachments. If a form matters, flatten it in your reader before splitting. Encrypted sources are refused outright rather than prompting for a password, since holding a password in browser memory would undercut the only promise this tool makes; remove the encryption first with the PDF Password Remover and split the clear copy.
Worked examples
Edge cases, worked step by step
The three examples above are the ordinary path. These three are the awkward ones — an open-ended range, an input the validator refuses, and a value that makes the split a no-op. Each is worked through with the same arithmetic the tool runs internally, so you can check the tool against the page.
If the goal is images rather than page subsets — one PNG or JPEG per page instead of one PDF per page — the PDF to JPG converter does that in one step and skips the split entirely.
Frequently asked questions
Sources & references
- ISO 32000-2 — PDF 2.0 specification (file header §7.5.2, trailer §7.5.5, page tree §7.7.3.2, object streams §7.5.8)
- pdf-lib — MIT-licensed pure-JavaScript PDF library used for the page-tree surgery
- pdf-lib source on GitHub (open-source, audited)
- MDN — File API (used for in-browser file reads, no upload)
The PDF header, trailer, and plan integrity validators were cross-checked against ISO 32000-2 on 2026-05-11. The pdf-lib dependency is pinned in package.json and re-verified on each major-version bump.
Related tools
Comments & feedback
Spotted a bug or want an improvement? Tell us — our team reviews every comment, and good ideas get built. Comments are public and anonymous.
Found a bug, edge case, or want to suggest an improvement?
Email me at [email protected] — most fixes ship within 24 hours.