DEV Community

Cover image for Why Local-First Web Apps are the Future: Building a Zero-Server PDF Engine with WebAssembly
Rick M
Rick M

Posted on

Why Local-First Web Apps are the Future: Building a Zero-Server PDF Engine with WebAssembly

Modern web applications are changing.

A few years ago, building a document editor, image compressor, or PDF toolkit almost always meant uploading files to a backend server, processing them remotely, and sending the results back to the user.

Today, modern browsers are powerful enough to perform many of those same tasks locally.

When building Fillora PDF, we re-evaluated our architecture and discovered that many common PDF operations didn't actually require a server. By moving supported workflows directly into the browser, we reduced unnecessary network requests while improving performance and privacy.

In this article, I'll explain what local-first means, the browser technologies that make it possible, and the engineering trade-offs we encountered along the way.


🏗️ What Does "Local-First" Mean?

A local-first application performs as much work as possible on the user's device before relying on cloud infrastructure.

Instead of treating the browser as a thin client, it becomes the primary execution environment.

For document applications, that means:

  • 📄 Opening files locally
  • ✏️ Editing documents in memory
  • 📥 Generating downloads without uploads
  • ☁️ Using the server only when it provides real value

Local-first doesn't mean eliminating servers completely.

Instead, it means choosing the right place to execute each workload.


🌐 Traditional Server-Centric Architecture

Many online document tools still follow this workflow:

Browser
    │
    ├── Upload File
    ▼
Cloud Server
    │
    ├── Process Document
    ▼
Browser
    └── Download Result
Enter fullscreen mode Exit fullscreen mode

Although straightforward, this architecture introduces several challenges:

  • Upload latency for large files
  • Higher bandwidth usage
  • Increased server CPU and memory consumption
  • Processing queues during peak traffic
  • Privacy concerns when handling sensitive documents

For many PDF editing operations, these round trips simply aren't necessary.


⚡ Browser-Native Architecture

Modern browsers already provide the APIs needed to process many documents locally.

Browser
    │
    ├── Read Local File
    ├── Process in Memory
    ├── Generate Output
    └── Download Result
Enter fullscreen mode Exit fullscreen mode

For supported workflows:

  • ✅ Documents remain on the user's device
  • ✅ No upload is required
  • ✅ Server CPU isn't consumed
  • ✅ Users receive results without waiting for upload and download cycles

🧩 Browser APIs That Make It Possible

The browser has evolved into a capable application runtime.

Several Web APIs make local-first document processing practical.


📂 FileReader API

The FileReader API allows applications to read files directly from a user's device.

const reader = new FileReader();

reader.onload = (event) => {
  console.log(event.target.result);
};

reader.readAsArrayBuffer(file);
Enter fullscreen mode Exit fullscreen mode

Perfect for:

  • Image previews
  • PDF editors
  • CSV importers
  • Markdown editors

📦 ArrayBuffer & Uint8Array

PDFs, images, and many other file formats are fundamentally binary data.

ArrayBuffer and Uint8Array allow JavaScript to manipulate those bytes efficiently without converting everything into strings.

These typed arrays are the foundation of many browser-native document tools.


💾 Blob & URL.createObjectURL()

After generating a new file, browsers can immediately create a downloadable object.

const url = URL.createObjectURL(blob);

const link = document.createElement("a");
link.href = url;
link.download = "merged.pdf";
link.click();

setTimeout(() => URL.revokeObjectURL(url), 0);
Enter fullscreen mode Exit fullscreen mode

Common use cases:

  • PDF generation
  • CSV exports
  • Image editors
  • ZIP downloads

Instead of uploading generated files back to a server, everything happens locally.


⚙️ Web Workers

Heavy JavaScript running on the main thread can freeze the user interface.

Web Workers move expensive computations into a background thread.

const worker = new Worker("worker.js");

worker.postMessage(data);

worker.onmessage = ({ data }) => {
  console.log(data);
};
Enter fullscreen mode Exit fullscreen mode

They're particularly useful for:

  • Large PDF processing
  • Image manipulation
  • OCR
  • Data parsing
  • Compression

Keeping long-running tasks off the main thread makes applications feel significantly more responsive.


📄 JavaScript PDF Libraries

Libraries like pdf-lib make browser-native PDF editing remarkably straightforward.

A simplified merge example looks like this:

import { PDFDocument } from "pdf-lib";

async function mergePdfFiles(buffers) {
  const mergedPdf = await PDFDocument.create();

  for (const buffer of buffers) {
    const pdf = await PDFDocument.load(buffer);

    const pages = await mergedPdf.copyPages(
      pdf,
      pdf.getPageIndices()
    );

    pages.forEach((page) => mergedPdf.addPage(page));
  }

  return await mergedPdf.save();
}
Enter fullscreen mode Exit fullscreen mode

For many everyday PDF operations, the entire workflow completes without requiring the document to leave the user's device.


🧠 Where WebAssembly Fits In

JavaScript is incredibly capable, but some workloads demand even more performance.

WebAssembly (Wasm) enables code compiled from languages like C, C++, or Rust to run securely inside the browser at near-native speed.

It's particularly valuable for computationally intensive tasks such as:

  • OCR engines
  • Image processing
  • Compression algorithms
  • Advanced rendering
  • Computer vision

Rather than replacing JavaScript, WebAssembly complements it by accelerating performance-critical components while JavaScript orchestrates the overall application.


⚖️ Engineering Trade-Offs

Local-first architecture isn't a silver bullet.

Several practical limitations remain.

1. Browser Memory Limits

Browsers enforce memory limits for each tab.

Very large PDFs or thousands of pages can exceed available memory, particularly on mobile devices.


2. Complex Document Formats

High-fidelity Office document rendering often depends on sophisticated rendering engines that are still better suited to dedicated backend services.


3. Bundle Size

Shipping every processing engine to every visitor would dramatically increase initial page load times.

Code splitting and lazy loading are essential for maintaining performance.


4. Hybrid Architectures Still Matter

Not every workload belongs in the browser.

A practical architecture combines:

  • Browser-native processing for supported editing tasks
  • Server-side processing for workloads that genuinely require backend compute

Choosing the right execution environment is often more important than forcing everything onto one side.


📈 What Changed

Moving supported PDF workflows into the browser produced several practical improvements.

✅ Reduced infrastructure costs

✅ Lower bandwidth consumption

✅ Faster perceived performance

✅ Better privacy for supported workflows

✅ Improved scalability by reducing dependency on server compute

Most importantly, backend resources became available for workloads that genuinely benefit from server-side processing.


💡 Lessons Learned

The browser has evolved far beyond rendering HTML.

Modern Web APIs, JavaScript, Web Workers, and WebAssembly make it possible to build applications that once required dedicated backend infrastructure.

Local-first architecture isn't about eliminating the cloud.

It's about using cloud resources intentionally while allowing capable client devices to perform the work they're already equipped to handle.


🎯 Final Thoughts

The future of many web applications isn't about moving everything to the server.

It's about moving the right workloads to the client.

For us, adopting a local-first approach led to faster interactions, improved privacy for supported workflows, and a more scalable architecture while still relying on server-side processing where it provides clear benefits.

As browsers continue to evolve, the line between desktop software and web applications will only become thinner.

If you're building document tools, editors, design software, or productivity applications, it's worth asking one simple question:

Does this operation really need to leave the user's device?

I'd love to hear how you're using browser APIs, WebAssembly, or local-first architecture in your own projects.


`
Enter fullscreen mode Exit fullscreen mode

Top comments (0)