Merge PDF Files
Combine multiple PDFs into one document — fully inside your browser, no signup, no upload. Drag to reorder, preview each file, and download the merged result. Pages stay byte-identical to the originals; 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 merge two PDFs you copy every page object from each source — together with everything it references (resources, fonts, images, content streams) — into a fresh document and rebuild a single page-tree root over the lot. That is what this tool does.
The merge is performed by pdf-lib, an MIT-licensed pure-JavaScript PDF library. It is loaded dynamically when you press Merge — 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.create() for the destination, PDFDocument.load(bytes) for each source, then copyPages(src, indices).addPage(...) for every page, and finally save() to serialise.
For each PDF the tool does five deterministic things before the merge:
- Validate the file. Confirms the PDF 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 version. The two ASCII digits inside the header give the PDF version (1.4 through 2.0 in real-world files). The version is shown on each queued row so you can spot a 2.0 file mixed with a 1.4 file before pressing Merge.
- Estimate page count. A heuristic byte-stream scan counts occurrences of
/Type /Page(excluding/Pages). This is fast and accurate on every uncompressed PDF and on most modern PDFs. PDFs that store every page object inside a compressed object stream (ISO 32000-2 §7.5.8) under-count here — the exact count is reported after the merge. - Order the queue. Files are merged in the order shown. Use the up and down arrows to nudge a file, or the trash icon to drop it. The page order in the output PDF mirrors the queue exactly.
- Merge and serialise. On Merge, pdf-lib creates a destination document, copies every page from each source (preserving the original byte streams), assigns them to the new page tree, writes a fresh catalog and trailer, and returns the merged byte buffer. That buffer is wrapped in a Blob and offered to you as a download via an object URL. No bytes leave the browser tab.
Worked examples
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 merge
- pdf-lib source on GitHub (open-source, audited)
- MDN — File API (used for in-browser file reads, no upload)
The PDF header and trailer 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.