DEV Community

sunshey
sunshey

Posted on

How to Merge Large PDFs in the Browser Without Crashing

Merging PDFs sounds simple until you hit a 200 MB file and your browser tab dies.

This is a real problem. I deal with it constantly — scanning reports, combining contract volumes, merging multi-chapter PDFs. Each one can be 50–100 MB. Merge three of them and you are looking at 300 MB of PDF data sitting in browser memory. Chrome doesn't like that.

Here is how I solved it with a Vue 3 + pdf-lib tool that handles large files without uploading anything.

The naive approach (and why it fails)

Most PDF merge tutorials show something like this:

// Load all files at once
const pdfDocs = await Promise.all(
  files.map(f => PDFDocument.load(await f.arrayBuffer()))
)

// Copy all pages from all docs
const merged = await PDFDocument.create()
for (const doc of pdfDocs) {
  const pages = await merged.copyPages(doc, doc.getPageIndices())
  pages.forEach(p => merged.addPage(p))
}
Enter fullscreen mode Exit fullscreen mode

This works for small files. But Promise.all loads every file into memory simultaneously. Three 80 MB PDFs = 240 MB sitting in RAM. Add the merged document on top and you are at 300+ MB. Browser tab crashes.

The fix: stream processing

Process files one at a time. After copying pages from each file, let the browser garbage-collect it before moving to the next:

import { PDFDocument } from 'pdf-lib'

async function mergeLargePdfs(files) {
  const merged = await PDFDocument.create()

  for (const file of files) {
    const bytes = await file.arrayBuffer()
    const sourcePdf = await PDFDocument.load(bytes)
    const pages = await merged.copyPages(sourcePdf, sourcePdf.getPageIndices())
    pages.forEach(page => merged.addPage(page))
    // sourcePdf is now eligible for GC
  }

  return await merged.save()
}
Enter fullscreen mode Exit fullscreen mode

Peak memory usage drops from ~300 MB to ~80 MB (the size of the largest single file). No more crashes.

Adding practical limits

In production, we also need hard limits to prevent the worst cases:

const MAX_FILE_SIZE = 100 * 1024 * 1024 // 100 MB
const MAX_FILES = 50

if (file.size > MAX_FILE_SIZE) {
  showError('File too large. Maximum 100 MB.')
  return
}

if (files.length > MAX_FILES) {
  showError('Maximum 50 files at once.')
  return
}
Enter fullscreen mode Exit fullscreen mode

These aren't arbitrary — they come from real user reports. At 100 MB per file, the merge is still snappy. Above that, users start complaining about lag.

UX lessons from a live tool

At en.sotool.top/merge, we learned:

  1. Show the file count and total size. Users want to know if they are about to merge 3 files or 30.
  2. Warn before processing. "This will take a moment" is better than a frozen UI.
  3. Allow reordering. Drag-and-drop file order matters more than you think.
  4. Track drop-off. How many users upload but never click "Merge"? That tells you if the UI is confusing.

When browser merging isn't enough

Even with streaming, there are limits:

  • Scanned PDFs with embedded images — each page can be 5–10 MB. A 200-page scanned manual is 1–2 GB. No browser can handle that.
  • Batch operations — merging, compressing, and watermarking the same 50 files? That's a desktop tool's job.
  • Memory-constrained devices — phones and tablets have less RAM. Large merges will fail there regardless of algorithm.

For these cases, try Wondershare PDFelement. It handles large files without crashing because it uses system memory, not browser memory.

Going further

The streaming approach works for most real-world merge scenarios. If you need to merge hundreds of files or handle scanned PDFs over 500 MB, a desktop tool is the right call. But for the majority of users — merging a handful of reports, contracts, or chaptered documents — a browser-based stream processor is fast, private, and free.

Want to see the full source? The site is built in public at github.com/sunshey/pdf-tool.


If you need desktop-grade PDF editing — large file merging, OCR, bookmarks, or batch workflows — check out Wondershare PDFelement.

Top comments (0)