The problem
Size limits break uploads exactly where people cannot walk away
A phone camera produces a 4 MB photo. A document portal accepts 2 MB. The error message says the file is too large and offers nothing else. No resize button, no guidance, no path forward. The person is left to figure out image compression on their own, mid task, on a phone.
I kept meeting this failure in health and government portals, the same everyday services my research program studies. It is a solved problem for engineers and an unsolved one for everyone else. The existing browser libraries were either heavy, abandoned, or silent about the one case that matters: what happens when compression would make the file bigger.

The bet
Why the browser, and why 2 kilobytes
The obvious architecture is a server: upload the image, compress it, send it back. I rejected it on three grounds. Privacy: photos of passports and medical documents should never transit a third party. Cost: a free tool with a server bill eventually stops being free. Latency: a round trip cannot beat work that finishes locally in under 100 ms.
Staying in the browser forced the discipline that defines the library. The core is pure Canvas API. No WASM, no bundled codecs, no dependencies. That keeps it at 2.3 KB min+gzip, roughly half the size of compressorjs and about nine times smaller than browser-image-compression. A library meant to fight bloat cannot itself be bloat.
The engineering
Three guarantees, four hundred lines
The whole core is five source files, 447 lines. Small enough to read in one sitting, which is the point: the guarantees are auditable.
Never a bigger file
Lossy output is guaranteed no larger than the source. When a format cannot beat an already efficient original, Compresso adapts quality and resolution instead of inflating. No rival library makes this guarantee.
Hit an exact size limit
Pass
maxSizeMB: 2and Compresso binary searches for the highest quality that fits under the cap. Built precisely for portals with hard upload limits.Modern formats, automatically
format: 'auto'picks AVIF, then WebP, then JPEG, per browser capability. The caller writes one line and every user gets the best format their browser can encode.
The API is one promise-based function with TypeScript types, an AbortSignal for cancellation, and a progress callback with named stages. The defaults are opinionated so the one-line call is already correct, and every default is documented with its reasoning.
The product
A library for developers, a tool for everyone else
The npm package solves the developer's problem. It does nothing for the person staring at the failed upload. So the same engine ships as a free tool: drop an image, see the before and after sizes, and download the result. It installs as a PWA and keeps working offline, because the entire pipeline is local by construction.
The tool doubles as the library's honest demo. The numbers on screen are not marketing figures. They are the engine running on your own photo, in your own browser.

Class comparison, verified July 2026
- compresso.js2.3 KB · 0 deps · HEIC + AVIF
- compressorjs4.5 KB · 2 deps
- browser-image-compression20.0 KB · 1 dep
- pica14.8 KB · 2 deps
Bundle sizes are minified CDN builds, gzipped, reproducible with curl and gzip. The docs also say when not to use Compresso: server batches belong to sharp, pixel editing to Jimp, pure downscaling quality to pica.
What is public
Code, benchmarks, and the roadmap
Everything is on the table: MIT licensed source, reproducible benchmark commands in the README, a changelog, a security policy, and a comparison that names its competitors and its own gaps. The next milestone is moving encode work into a Web Worker for v1.0, so large images never block the main thread.
Compresso is small by intent and honest by policy. It is what I think open source infrastructure should look like: one problem, fully solved, at the minimum possible cost to the people who adopt it.