Most devs reach for Cloudinary, Squoosh CLI, or a Node backend to optimize images.
But what if you could do production-grade image compression — including WebP and MozJPEG — directly in the browser, using WebAssembly? No server, no upload, no cost.
Here’s how to build your own browser-based image optimizer using WebAssembly and wasm-bindgen
.
Step 1: Use precompiled WASM codecs via Squoosh
Google’s Squoosh project exposes production-ready WASM image codecs like MozJPEG, WebP, and AVIF — and you can use them in your own app.
Install the core codecs:
npm install @squoosh/lib
Then load a codec like MozJPEG:
import { ImagePool } from '@squoosh/lib';
const imagePool = new ImagePool();
Step 2: Accept user uploads and compress in-browser
Set up an input to handle image uploads:
Now optimize the file:
async function handleFile(event) {
const file = event.target.files[0];
const arrayBuffer = await file.arrayBuffer();
const image = imagePool.ingestImage(arrayBuffer);
await image.encode({
mozjpeg: {
quality: 70,
},
});
const encoded = await image.encodedWith.mozjpeg;
const blob = new Blob([encoded.binary], { type: 'image/jpeg' });
// Optionally download it
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'optimized.jpg';
a.click();
}
Step 3: Support Other Codecs (WebP, AVIF, etc.)
Swap mozjpeg
for webp
or avif
to support modern formats:
await image.encode({
webp: {
quality: 80,
},
});
You can even expose a UI to let users choose the output format.
Step 4: Optional React Hook for Integration
To make this reusable across your app, extract it into a hook:
function useImageOptimizer() {
const imagePool = useMemo(() => new ImagePool(), []);
const optimize = async (file, format = 'mozjpeg') => {
const arrayBuffer = await file.arrayBuffer();
const image = imagePool.ingestImage(arrayBuffer);
await image.encode({ [format]: { quality: 75 } });
const encoded = await image.encodedWith[format];
return new Blob([encoded.binary], { type: \`image/\${format}\` });
};
return { optimize };
}
✅ Pros:
- Completely serverless — all image processing happens client-side
- Supports WebP, MozJPEG, and AVIF with production-quality compression
- Great for PWAs, CMS apps, or privacy-first tools (no upload)
⚠️ Cons:
- WASM codecs are large (~1MB+), so initial load is heavier
- Processing is memory/CPU intensive — slower on low-end devices
- Not ideal for batch-processing large volumes
Summary
With just a few lines of JavaScript and Google’s prebuilt WASM codecs, you can build a browser-based image optimizer that rivals many SaaS tools. This approach keeps images private, requires no backend infrastructure, and provides full control over format and quality. It’s ideal for privacy-sensitive apps, PWAs, or anytime you want to offload work to the client without sacrificing performance.
Next time you consider reaching for a third-party API or spinning up a Lambda just to optimize images, remember — the browser can do it all.
If this was helpful, you can support me here: Buy Me a Coffee ☕