DEV Community

Atomlit Labs
Atomlit Labs

Posted on

Building a 100% Client-Side PDF Editor: Why I Chose Astro and WebAssembly

The Privacy Problem with Online PDF Tools

We’ve all been there: you need to merge two PDFs or edit a quick detail, so you Google "PDF editor." You find a dozen sites, upload your sensitive document (maybe an invoice or a contract), and hope for the best.

As a developer, this always felt like a massive privacy hole. Why should my data live on someone else's server just to perform a simple merge operation?

That’s why I decided to build DumPDF—a tool that does everything strictly in the browser. No uploads, no servers, just your files and your CPU.

The Architecture: Why Astro + TypeScript?

When building a tool that needs to be fast and SEO-friendly, I chose Astro.

Astro's "islands" architecture is perfect here. Since the PDF manipulation happens entirely on the client side, I didn't need a heavy backend. I used Astro to ship zero-JavaScript by default for the landing pages, only loading the heavy libraries (like pdf-lib and tesseract.js) when the user actually starts an "action."

Key dependencies in the stack:

pdf-lib: To handle the heavy lifting of merging, splitting, and modifying PDF bytes.

Tesseract.js: For OCR (Optical Character Recognition) so I can make images searchable without sending them to a cloud AI.

Tailwind CSS: For a utility-first, responsive UI.

The Technical Challenge: Handling Bytes in the Browser
The trickiest part of keeping everything offline is managing memory. Handling large PDF files in a browser tab can easily crash the main thread.

Here is a simplified look at how I handle a PDF merge using pdf-lib:

TypeScript

import { PDFDocument } from 'pdf-lib';

async function mergePDFs(files: FileList) {
  const mergedPdf = await PDFDocument.create();

  for (const file of Array.from(files)) {
    const bytes = await file.arrayBuffer();
    const pdf = await PDFDocument.load(bytes);
    const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices());
    copiedPages.forEach((page) => mergedPdf.addPage(page));
  }

  const mergedPdfBytes = await mergedPdf.save();
  // We trigger a local download here using file-saver
  return mergedPdfBytes;
}
Enter fullscreen mode Exit fullscreen mode

Why "Offline-First" Matters in 2026

Building this taught me that we often over-complicate web apps with expensive cloud infrastructure. For most PDF manipulations, modern browser engines are more than capable of handling the work.

Benefits of this approach:

Speed: No upload/download latency.

Cost: Static hosting on Cloudflare is essentially free.

Trust: Users can literally turn off their internet and the tool still works.

What’s Next?

DumPDF is currently live. It's been a journey in exploring how much we can push the boundaries of "Client-Side Only" applications.

I’d love to hear from the community: Have you experimented with moving traditionally "server-side" tasks to the client? What libraries are you using to handle large file manipulations?

Top comments (0)