How to Merge, Split, and Rotate PDFs in Your Browser (No Upload Required)
June 5, 2026 · 4 min read
PDF editing used to mean uploading your files to a third-party server, hoping it stays private, and waiting for a download link. Modern browsers make a better approach possible: process PDFs entirely in JavaScript, in your browser tab, with no data ever leaving your device.
This guide covers how to merge, split, rotate, and convert PDFs using the pdf-lib library — and why client-side PDF tools are the right choice for privacy-sensitive documents.
Why process PDFs in the browser?
When you upload a PDF to an online tool:
- Your data leaves your device — even if the provider promises deletion, you can't verify it.
- Sensitive documents (contracts, tax returns, medical records) are transmitted over the internet.
- Files may be stored, scanned, or indexed depending on the provider's terms.
Client-side processing eliminates this entirely. The file stays in browser memory; nothing is transmitted.
The pdf-lib library
pdf-lib is a pure-JavaScript PDF manipulation library that runs in the browser with no dependencies on Node.js or a server. It supports:
- Creating new PDF documents
- Loading and modifying existing PDFs
- Copying pages between documents
- Rotating pages
- Embedding JPEG and PNG images
It does not support rendering PDF pages as images (for that you'd need PDF.js) or OCR.
Merging PDFs
To merge two or more PDFs, load each into a PDFDocument, copy their pages into a new document, and save:
import { PDFDocument } from 'pdf-lib';
async function mergePdfs(files) {
const merged = await PDFDocument.create();
for (const file of files) {
const buf = await file.arrayBuffer();
const doc = await PDFDocument.load(buf);
const pages = await merged.copyPages(doc, doc.getPageIndices());
pages.forEach(p => merged.addPage(p));
}
const bytes = await merged.save();
return new Blob([bytes.buffer], { type: 'application/pdf' });
}
Key notes:
getPageIndices()returns[0, 1, 2, ...]for all pagescopyPagesreturns cloned page objects you thenaddPageto the destination- Order files before calling — the merge preserves insertion order
Ready to use: PDF Merge →
Splitting a PDF by page range
To extract pages 2–4 from a 10-page PDF:
const { PDFDocument } = await import('pdf-lib');
const src = await PDFDocument.load(await file.arrayBuffer());
const out = await PDFDocument.create();
const pages = await out.copyPages(src, [1, 2, 3]); // 0-indexed
pages.forEach(p => out.addPage(p));
const bytes = await out.save();
Parse a range string like "2-4, 7, 9" into zero-based indices before calling copyPages.
Ready to use: PDF Split →
Rotating pages
pdf-lib stores rotation as part of the page's dictionary. Use setRotation with the built-in degrees helper:
const { PDFDocument, degrees } = await import('pdf-lib');
const doc = await PDFDocument.load(await file.arrayBuffer());
const pages = doc.getPages();
for (const page of pages) {
const current = page.getRotation().angle;
page.setRotation(degrees((current + 90) % 360));
}
const bytes = await doc.save();
Rotations are cumulative — if a page already has a 90° rotation metadata and you add another 90°, it becomes 180°.
Ready to use: PDF Rotate →
Removing pages
Removing pages works by copying only the pages you want to keep:
const pagesToRemove = new Set([0, 3]); // remove page 1 and page 4
const allIndices = Array.from({ length: doc.getPageCount() }, (_, i) => i);
const keepIndices = allIndices.filter(i => !pagesToRemove.has(i));
const out = await PDFDocument.create();
const pages = await out.copyPages(doc, keepIndices);
pages.forEach(p => out.addPage(p));
Ready to use: PDF Page Remover →
Converting images to a PDF
pdf-lib can embed JPEG and PNG images natively. For WebP, draw to a canvas first and export as PNG:
async function imageToPdfPage(doc, file) {
const data = new Uint8Array(await file.arrayBuffer());
const img = file.type === 'image/jpeg'
? await doc.embedJpg(data)
: await doc.embedPng(data);
const { width: iw, height: ih } = img;
const page = doc.addPage([iw, ih]); // fit page to image
page.drawImage(img, { x: 0, y: 0, width: iw, height: ih });
}
To fit the image to a standard page size (A4, Letter), scale to fit:
const [pageW, pageH] = [595, 842]; // A4 in points
const scale = Math.min(pageW / iw, pageH / ih);
const x = (pageW - iw * scale) / 2;
const y = (pageH - ih * scale) / 2;
page.drawImage(img, { x, y, width: iw * scale, height: ih * scale });
Ready to use: Images to PDF →
File sizes and limitations
- pdf-lib keeps the entire PDF in memory as a
Uint8Array. Large PDFs (50+ MB) may cause the tab to slow down on low-memory devices. - Encrypted PDFs cannot be loaded unless you supply the password (pdf-lib does not attempt brute-force decryption).
- pdf-lib does not render pages as images — use PDF.js for that.
Privacy checklist
✅ No API calls: the PDF never leaves the browser
✅ Works offline: once loaded, no internet required
✅ No tracking: operations are pure in-memory computation
✅ Free: the tools linked above have no usage limits
For compressing images before converting, use the Image Compressor first. To resize images, try the Image Resizer.