Why it exists
A size limit is a design failure that arrives as your fault.
A phone photo is routinely several megabytes. The form that rejects it allows five, and it will not tell you what to change. Compresso absorbs that problem back into the browser, where it takes under a second.
- 0 bytes
Uploaded, ever
Open your network tab and watch it stay silent while a hundred photos process.
- 3.3 MB to 93.5 KB
One measured run
Results vary by content, so this is a single real result rather than an average we have not benchmarked.
- 3.6 KB
Library core, gzipped
Zero required dependencies. Browser primitives only.
The app
Everything happens on your device.
Free, installable, and built for the moment you have forty photos and a form that will not take any of them.
Private by construction
There is no server to send your photos to. This is not a policy you have to trust, it is an architecture you can verify.
Works with no connection
Install it once and it runs on a plane. The interface, the fonts, and the HEIC decoder are all stored on your device.
A hundred at a time
Images are processed in parallel across your CPU cores, so the interface stays smooth while a large batch runs.
iPhone photos included
Reads HEIC, JPEG, PNG, WebP, and AVIF. Writes AVIF, WebP, JPEG, and PNG, choosing the best format your browser can produce.
Seven languages
English, Spanish, French, German, Italian, Portuguese, and Chinese, with sizes and percentages formatted the way each locale writes them.

For developers
The same engine, as a dependency.
If you would rather your users never meet an upload error, the compression core ships as a library you can drop into any framework.
import { compress } from 'compresso.js';
const { file, savings } = await compress(input, {
quality: 0.8,
format: 'auto',
});3.6 KB, gzipped
Small enough that adopting it does not need a meeting. Zero required dependencies, and nothing to audit.
Parallel batch compression, off the main thread
compresso.js/pool runs a resilient Web Worker pool — crash and timeout recovery included — so a big batch compresses in parallel without blocking your interface.
Never returns a bigger file
Lossy output is capped at the smaller of your size limit and the original, because a compressor that can grow a file is broken.
