DEV Community

Ashan Nandasena
Ashan Nandasena

Posted on

I Built a 100% Client-Side File Converter (No Server Uploads) — Here's What I Learned

I Built a 100% Client-Side File Converter (No Server Uploads) — Here's What I Learned

Hey dev.to! 👋

I recently built Easy2Convert.xyz, a file converter that runs entirely in the browser. No servers, no uploads, no privacy concerns.

Here is the story of how I built it, the architecture behind it, and what I learned about browser-based file manipulation.

TL;DR: Built a privacy-first file converter using Next.js + pdf.js + Canvas API. Zero server uploads, works offline via Service Workers, handles HEIC/WebP via WASM. Try it: easy2convert.xyz


Why I Built This

Most online converters upload your files to their servers. For sensitive documents (contracts, IDs, financial records, family photos), this is a massive privacy risk.

Many security researchers have highlighted that free online tools often retain uploaded files longer than their stated retention policies — sometimes indefinitely. Even if they claim to delete files after an hour, you have no way to verify it.

I wanted to build a tool that gives users 100% control and ownership of their data by processing everything locally in the client-side sandbox.


Tech Stack & Architecture

To achieve serverless file conversion, the project is built on:

  • Next.js 14 (App Router) for a fast, responsive UI with SSR benefits
  • pdf.js for client-side PDF rendering, text extraction, and manipulation
  • HTML5 Canvas API for client-side image decoding, scaling, and compression
  • Web Workers to offload heavy computations from the main thread, keeping the UI smooth
  • WebAssembly (WASM) libraries for HEIC decoding on non-Apple devices
+-----------------------------------------------------------------+
| LOCAL BROWSER SANDBOX (Client-Side Architecture)               |
|                                                                 |
|   📁 File Read → Local RAM ArrayBuffer                         |
|   ⚙️ WebAssembly / Canvas Engine Decodes Binary Locally        |
|   📦 Instant Output Blob Generated                             |
|   🔒 ZERO bytes uploaded to external servers                   |
|                                                                 |
+-----------------------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode

Key Learnings & Challenges

1. Browser Memory Limits

Web browsers aren't designed to load gigabytes of data into RAM. We ran into memory issues when dealing with files larger than 50MB.

The biggest culprit? Forgetting to release object URLs after download:

// ❌ Memory leak - object URL never released
const url = URL.createObjectURL(blob);
downloadLink.href = url;

// ✅ Proper cleanup - prevents memory leaks
const url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.addEventListener('click', () => {
  setTimeout(() => URL.revokeObjectURL(url), 1000);
});
Enter fullscreen mode Exit fullscreen mode

Using Blob objects efficiently and releasing object URLs immediately after download helped optimize garbage collection significantly.

2. HEIC and WebP Decoding

Browsers do not natively support all image formats — especially HEIC on non-Apple devices. We integrated lightweight decoding libraries compiled to WebAssembly to bridge this gap at near-native speeds.

The tradeoff? WASM binaries add ~2-3MB to the initial bundle. We solved this with dynamic imports:

// Load HEIC decoder only when user uploads a .heic file
const convertHEIC = async (file) => {
  const { default: heic2any } = await import('heic2any');
  return heic2any({ blob: file, toType: 'image/jpeg' });
};
Enter fullscreen mode Exit fullscreen mode

3. Service Workers for Offline Support

Since no server is involved in the conversion, once the assets are loaded, the converter can function fully offline. Service Workers cache the core engines so users can convert files even mid-flight (literally — tested on airplane WiFi mode ✈️).

We used next-pwa with a CacheFirst strategy for static assets and Google Fonts. Once cached, the entire conversion pipeline works without any network connection.

4. The "Trust" Problem

Even with 100% client-side processing, users were skeptical. "How do I know you're not uploading my files?"

Our solution:

  • Open architecture explanation on the homepage
  • Network tab verification instructions in our FAQ
  • Brand disclaimer separating us from legacy desktop software with similar names

Lesson: Privacy isn't just about what you do — it's about proving it to users.


Performance Optimization Journey

Initial Lighthouse scores were rough (Mobile: 62, Desktop: 78). Here's how we got to Mobile: 85+, Desktop: 90+:

Optimization Impact
Dynamic imports for heavy libs (pdf.js, heic2any) +12 pts
Canvas animations disabled on mobile +8 pts
AdSense script → lazyOnload strategy +5 pts
Image optimization with Next.js Image component +3 pts
Font preconnect + display=swap +2 pts

Check It Out

The site is fully responsive, free, and has no annoying download timers:

👉 easy2convert.xyz

Features:

  • 🖼️ Image Converter (HEIC, WebP, PNG, JPG)
  • 📄 PDF to Word / Word to PDF
  • ✏️ In-Browser PDF Editor (erase, redact, sign)
  • ⚡ Base64 Encoder/Decoder
  • 🧮 Developer Calculators Suite

What's Next

  • [ ] Batch conversion support (multiple files at once)
  • [ ] OCR for scanned PDFs (using Tesseract.js WASM)
  • [ ] PWA install prompt for true offline-first experience
  • [ ] Dark mode (because every dev tool needs one 😄)
  • [ ] Open-source the core conversion engine on GitHub

If you have feature requests, architectural suggestions, or want to contribute, drop a comment below! 👇

Would love feedback from the community on local binary processing patterns! 🙏


Built with ❤️ using Next.js, pdf.js, and a stubborn belief that your files should never leave your device.

Top comments (0)