I merge PDFs about twice a week. Not enough to pay for an Adobe subscription, but enough to be annoyed by online tools.
You know the drill:
Google "merge pdf free".
Upload your private bank statement to a random server.
Get hit with a "Daily Limit Reached" popup just when you need to download the result.
I got tired of this. I realized that modern browsers and WebAssembly are fast enough to handle PDF manipulation client-side. We don't actually need a backend for this anymore.
So, I built Simple VaultPDF.
The Tech Stack
I wanted to keep it lightweight and 100% offline.
Framework: React (Vite)
PDF Engine: pdf-lib (for merging/splitting) & pdf.js (for rendering)
OCR: tesseract.js
State: Just React hooks, kept it simple.
The Code (How it works)
The coolest part is that pdf-lib lets you manipulate binary data directly in the browser memory. Here is the core function that merges files without sending a single byte to a server:
JavaScript
import { PDFDocument } from 'pdf-lib';
const mergeFiles = async (files) => {
const mergedPdf = await PDFDocument.create();
for (const file of files) {
const fileBuffer = await file.arrayBuffer();
const pdf = await PDFDocument.load(fileBuffer);
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
copiedPages.forEach((page) => mergedPdf.addPage(page));
}
const pdfBytes = await mergedPdf.save();
return pdfBytes;
};
Why Local-First?
Building it as a Chrome Extension instead of a website had huge benefits:
Zero Server Costs: Since I don't process the files, I don't pay for AWS/Cloud functions.
Privacy: Users don't have to trust me with their data, because the data never leaves their machine.
Speed: No upload/download latency.
The Result
It's currently an MVP. It handles merging, reordering, and rotation perfectly. I also added basic OCR because why not.
I just published it to the Chrome Web Store. If you are tired of paywalls or just want to see how pdf-lib performs in a real extension, give it a try.
Link: Simple VaultPDF on Chrome Web Store
Let me know if you find any bugs! I'm still optimizing the memory usage for large files.
Happy coding!
Top comments (0)