I used to hate dealing with PDFs.
Every time I needed to merge two pages of a bank statement or compress an identity document for a government portal, my only option was to Google "free PDF compressor" and upload my sensitive files to a random server halfway across the world.
As a developer, that felt completely wrong. Why do my files need to leave my machine just to get compressed or merged?
I decided to solve my own problem and build PDF Pro AI—a 100% private, zero-upload document workspace. The rule was simple: all processing had to happen locally in the user's browser.
Here is exactly how I architected a serverless PDF editor using WebAssembly, React, and Next.js, and why you should consider moving heavy computation to the client side.
The Problem with Cloud PDF Tools
Most free PDF tools use a standard architecture:
You upload your file.
The server spins up a heavy Python or Node.js process using libraries like PyPDF2 or Ghostscript.
It does the manipulation.
You download the result.
The server (hopefully) deletes your file.
This is slow, expensive to scale, and fundamentally a massive privacy risk. If a user is uploading a highly confidential NDA or a bank statement, they have to trust that your cron job actually deletes the file.
I wanted to eliminate the server entirely.
Enter WebAssembly (WASM) and pdf-lib
To do heavy document manipulation without a backend server, I turned to WebAssembly.
Specifically, I built the core engine around pdf-lib, a fantastic JavaScript library that works beautifully in modern browsers. Instead of relying on a server to crunch the bytes, pdf-lib leverages the user's own CPU to modify the PDF structure locally.
Here is what the architecture looks like for merging two PDFs directly in the browser:
import { PDFDocument } from 'pdf-lib';
async function mergePDFsLocally(files) {
// Create a brand new, empty PDF document
const mergedPdf = await PDFDocument.create();
for (const file of files) {
// Read the user's file as an ArrayBuffer directly from the file input
const arrayBuffer = await file.arrayBuffer();
// Load it into pdf-lib
const pdf = await PDFDocument.load(arrayBuffer);
// Copy all pages from the source PDF
const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
// Append them to our new document
copiedPages.forEach((page) => mergedPdf.addPage(page));
}
// Serialize the final document to bytes
const mergedPdfBytes = await mergedPdf.save();
// Create a local blob URL for the user to download instantly
const blob = new Blob([mergedPdfBytes], { type: 'application/pdf' });
return URL.createObjectURL(blob);
}
The Magic of the Blob URL
Look closely at the last three lines of that code snippet. That is where the magic happens.
When the PDF is finished merging, I convert the raw bytes into a Blob and generate an Object URL using URL.createObjectURL().
This creates a temporary, local-only download link that looks something like blob:https://www.pdfpro.co.in/5b8f.... The file never touched an S3 bucket. It never hit an API endpoint. The entire operation happened in the RAM of the user's laptop.
The result? The merge happens in less than 50 milliseconds, and the user's privacy is mathematically guaranteed because the file literally cannot leak.
Handling Compression with PDF.js
Merging is relatively straightforward, but what about compressing?
Compressing a PDF locally is notoriously difficult because you essentially have to re-render the document and strip out unoptimized metadata. For this, I combined pdf-lib with Mozilla's pdf.js worker.
The workflow I built does the following:
pdf.js reads the document and extracts the raw text and image assets on a background web worker thread (so the UI doesn't freeze).
I compress the extracted images locally using HTML5 rendering.
pdf-lib reconstructs the PDF using the newly compressed assets.
It took a lot of trial and error to get the memory management right—large PDFs can easily crash a browser tab if you don't aggressively clear your ArrayBuffers for garbage collection—but the final product is incredibly fast.
Why This Matters for Indie Hackers
Moving heavy workloads to the browser isn't just about privacy; it is an incredible cost-saving hack for solo founders.
Because PDF Pro doesn't rely on expensive cloud functions or heavy backend storage buckets for standard document editing, my AWS/Vercel bill for that specific feature is exactly $0.00. The users provide their own compute power. I just provide the WebAssembly instructions.
If you are building a tool that manipulates images, audio, video, or documents, I highly recommend exploring WebAssembly and client-side processing before reaching for a server. Your users will love the privacy, and you will love the hosting bill.
Rahul Banerjee is a software engineer and the creator of PDF Pro AI, a privacy-first document workspace featuring local PDF tools and AI-powered contract analysis.