Documentation
Installation
Install via npm, yarn, or pnpm:
npm install compresso.js
# or
yarn add compresso.js
# or
pnpm add compresso.jsOr use directly from a CDN:
<script src="https://unpkg.com/compresso.js/dist/compresso.umd.js"></script>Quick Start
import { compress } from 'compresso.js';
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const result = await compress(file, {
quality: 0.8,
maxWidth: 1920,
format: 'webp',
});
console.log(`${result.savings}% smaller`);
// result.file → optimized File, ready for upload
// result.url → object URL for preview
});API Reference
compress(source, options?)
Compresses a single image. Accepts a File, Blob, or image URL string.
compressMultiple(files, options?)
Compresses an array of files sequentially.
createCompressor(defaults?)
Creates a reusable compressor instance with preset options:
const optimizer = createCompressor({
quality: 0.7,
maxWidth: 1200,
format: 'webp',
});
const result = await optimizer.compress(file);Options
| Option | Type | Default | Description |
|---|---|---|---|
quality | number | 0.8 | Output quality, 0 to 1 |
maxWidth | number | Infinity | Maximum output width in pixels |
maxHeight | number | Infinity | Maximum output height in pixels |
format | string | 'auto' | 'jpeg' | 'png' | 'webp' | 'avif' | 'auto' |
maxSizeMB | number | Infinity | Maximum file size in MB |
maxInputPixels | number | 100_000_000 | Max decodable input resolution (width × height); guards against a crafted file declaring an enormous resolution. Infinity to disable |
backgroundColor | string | '#ffffff' | Background color for transparent → JPEG |
onProgress | function | none | Progress callback |
signal | AbortSignal | none | Cancel compression |
Result Object
| Property | Type | Description |
|---|---|---|
file | File | Optimized File object |
blob | Blob | Optimized Blob |
url | string | Object URL for preview |
width | number | Output width |
height | number | Output height |
originalSize | number | Original size in bytes |
compressedSize | number | Compressed size in bytes |
savings | number | Reduction percentage |
format | string | Output format |
Target File Size
Set maxSizeMB to ensure the output never exceeds a given file size. Compresso uses binary search to find the highest quality that fits:
const result = await compress(file, {
maxSizeMB: 2, // Output will be ≤ 2 MB
format: 'jpeg',
});Batch & Workers
New in 1.0.0: compresso.js/pool runs many compressions in parallel, off the main thread, via a resilient Web Worker pool — no UI jank on a 50-photo upload.
import { createPool } from 'compresso.js/pool';
const pool = createPool();
const results = await pool.compressMany(fileList, { format: 'auto' }, (e) => {
console.log(`${e.fileIndex + 1}/${e.totalFiles} — ${Math.round(e.overallProgress * 100)}%`);
});
for (const r of results) {
if (r.status === 'fulfilled') uploads.push(r.value.file);
}
pool.destroy();createPool() never throws for lack of Worker support — it falls back to the exact same API on the main thread automatically. A worker that crashes or goes silent past a timeout is detected and replaced (visible via pool.stats().recoveries). compressMany() results are Promise.allSettled-shaped, so one failed file never sinks the rest of the batch.
Progress Tracking
const result = await compress(file, {
onProgress: ({ progress, stage }) => {
console.log(`${stage}: ${Math.round(progress * 100)}%`);
// loading: 10% → resizing: 30% → compressing: 50-90% → done: 100%
},
});Cancellation
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const result = await compress(file, {
signal: controller.signal,
});
} catch (err) {
if (err.name === 'AbortError') {
console.log('Compression was cancelled');
}
}Format Detection
import { isFormatSupported, getBestFormat, detectFormat } from 'compresso.js';
// Check if the current browser supports AVIF
isFormatSupported('avif'); // true or false
// Get the best format the browser supports
getBestFormat(); // 'avif', 'webp', or 'jpeg'
// Detect format from a file
detectFormat(file); // 'png', 'jpeg', etc.Framework Guides
React
import { useState } from 'react';
import { compress, formatBytes } from 'compresso.js';
function ImageUpload() {
const [result, setResult] = useState(null);
async function handleFile(e) {
const file = e.target.files[0];
if (!file) return;
setResult(await compress(file, { quality: 0.8, format: 'webp' }));
}
return (
<div>
<input type="file" accept="image/*" onChange={handleFile} />
{result && (
<p>{formatBytes(result.originalSize)} → {formatBytes(result.compressedSize)} ({result.savings}% smaller)</p>
)}
</div>
);
}Vue
<script setup>
import { ref } from 'vue';
import { compress } from 'compresso.js';
const result = ref(null);
async function handleFile(e) {
const file = e.target.files[0];
if (!file) return;
result.value = await compress(file, { quality: 0.8, format: 'webp' });
}
</script>
<template>
<input type="file" accept="image/*" @change="handleFile" />
<p v-if="result">{{ result.savings }}% smaller</p>
</template>Vanilla JS (CDN)
<script src="https://unpkg.com/compresso.js/dist/compresso.umd.js"></script>
<script>
document.getElementById('upload').addEventListener('change', async (e) => {
const result = await Compresso.compress(e.target.files[0], {
quality: 0.8,
format: 'webp',
maxSizeMB: 2,
});
console.log(result.savings + '% smaller');
});
</script>Browser Support
| Browser | JPEG/PNG | WebP | AVIF |
|---|---|---|---|
| Chrome 32+ | ✓ | ✓ | ✓ (85+) |
| Firefox 29+ | ✓ | ✓ (96+) | ✓ (113+) |
| Safari 8+ | ✓ | ✓ (16+) | ✓ (16.4+) |
| Edge 79+ | ✓ | ✓ | ✓ (121+) |
When using format: 'auto', Compresso automatically detects the best format supported by the current browser.
Why optimize in the browser?
Client side optimization means the server receives an already optimized file. No server side processing, no GPU instances, no image processing libraries to maintain. The heavier the traffic, the more you save, because each user’s device does the work.
| Server-side processing | Client-side (Compresso) | |
|---|---|---|
| Infrastructure cost | Scales with traffic | Zero (user's device) |
| Processing latency | 200 to 2000ms per image | <100ms |
| Works offline | No | Yes |
| Image leaves device | Yes (uploaded raw) | Only optimized version |
| Server dependencies | Sharp, ImageMagick, etc. | None |
Open the app · FAQ · Compare · Examples