Image compression APIs and libraries for developers

For automating compression at scale, the choice is between a library you run and a service you call. Both are reasonable; they fail in different ways.

The landscape

sharp (Node)
The default for JavaScript. Wraps libvips — fast, low memory.
libvips
The engine underneath sharp. Bindings for Python, Ruby, Go, PHP and more.
ImageMagick
The generalist. Does everything, uses far more memory on large files.
Pillow (Python)
The Python standard. Convenient, slower than libvips at scale.
MozJPEG
The encoder, not a library. Smallest standard JPEGs.
oxipng / libwebp / libavif
Format-specific encoders, usually invoked by the above.
Hosted APIs and image CDNs
Transform on request. No infrastructure, ongoing cost.

Choosing an approach

Run a library, or call a service

A library runs in your own process. You pay in CPU and memory, you control the versions, and nothing leaves your infrastructure. Best when you have a defined set of images to process at build time, or when the content is sensitive.

A hosted service transforms on request, usually driven by URL parameters, and caches the result. You pay per image or per bandwidth, and you get formats you may not want to build for — AVIF in particular. Best for large or user-generated catalogues where pre-generating every variant is impractical.

The failure modes differ, and that is usually what decides it. A library fails by consuming your server's memory under load. A service fails by being down, changing its pricing, or sitting in the critical path of every page you serve.

sharp and libvips

For Node, sharp is the default and deserves to be. It wraps libvips, which processes images in a streaming fashion rather than loading the whole thing into memory — the practical result is that it handles large images in a fraction of the memory ImageMagick needs, and considerably faster.

import sharp from "sharp";

await sharp(input)
  .resize({ width: 1600, withoutEnlargement: true })
  .webp({ quality: 78 })
  .toFile("out.webp");

withoutEnlargement is the option people forget; without it sharp will upscale a small image without complaint. libvips itself has bindings for Python, Ruby, Go, PHP and others, so the same engine is available outside Node.

When ImageMagick is still right

ImageMagick does far more than resize and compress — composition, effects, format conversion across dozens of formats, PDF and PostScript handling. If you need that breadth, its memory cost is the price.

For a pipeline that only resizes and compresses, libvips is faster and lighter, and the difference becomes significant under concurrency. Choose ImageMagick for capability, libvips for throughput.

The encoders underneath

Libraries generally delegate the actual encoding, and you can often choose what they delegate to.

MozJPEG
Typically 5–15% smaller JPEGs than standard libjpeg at matched quality. Output is an ordinary JPEG.
jpegli
Newer, from the JPEG XL team, targeting better quality per byte while staying fast. Worth benchmarking against your own content.
libwebp
The reference WebP encoder. Fast enough for on-demand use.
libavif
AVIF encoding. Slow — fine at build time, generally not viable in a request cycle.
oxipng
Lossless PNG optimisation, considerably faster than optipng.

Practical advice for a pipeline

  • Resize before encoding. The same rule as everywhere else, and it also cuts your CPU cost.
  • Cap input dimensions. A user-uploaded 100-megapixel image will exhaust a worker. Reject or downscale on arrival.
  • Set concurrency deliberately. Image processing is CPU-bound; unbounded parallelism will take the server down rather than speed it up.
  • Cache aggressively. Never transform the same image twice — content-hash the output and cache for a year.
  • Strip metadata explicitly. Most libraries preserve it by default, so user uploads keep their GPS coordinates unless you say otherwise.
  • Convert to sRGB. Otherwise wide-gamut uploads will look wrong in browsers that ignore the profile.

Why this site does not have an API

An API would mean receiving your files, which is the one thing this site is built not to do. Every tool here runs in the visitor's browser, and there is no server-side image path to expose.

If you need programmatic compression, use sharp or libvips in your own infrastructure, or a hosted service chosen knowingly. Those are the right tools for that job, and pretending otherwise would not help you.

Try it yourself

Everything below runs in your browser, so you can test any of this on your own files without uploading them.

  • Bulk compressor

    One setting across a whole folder, processed in parallel, downloaded as a ZIP.

    Open the tool
  • JPG to WebP

    Typically 25–35% smaller at matched quality. The standard web win.

    Open the tool
  • Compress JPEG

    Shrink JPG and JPEG photographs with a quality slider or an exact target size.

    Open the tool

Questions

Frequently asked questions

Every answer below is present in the page source, expanded, so it can be read without opening anything.

What is the best image processing library for Node?

sharp, for almost every case. It wraps libvips, which is fast and uses far less memory than ImageMagick on large files, and it is what most framework image integrations use internally.

Should I use a hosted image API or run my own?

Run your own for a defined set of images processed at build time, or when content is sensitive. Use a hosted service for large or user-generated catalogues where pre-generating every variant is impractical — accepting the ongoing cost and the external dependency.

Is ImageMagick still worth using?

For breadth, yes — it handles composition, effects and formats libvips does not. For a pipeline that only resizes and compresses, libvips is faster and much lighter on memory, which matters under concurrency.

Which encoder gives the smallest files?

MozJPEG for JPEG, typically 5–15% below standard libjpeg at matched quality. libavif produces smaller files still but is slow enough that it is really only viable at build time. jpegli is newer and worth benchmarking.

How do I stop large uploads crashing my server?

Cap input dimensions on arrival and reject anything beyond a sensible megapixel limit, then bound your processing concurrency. Image work is CPU-bound and memory-hungry, and unbounded parallelism takes servers down.

Does this site have an API?

No, and it will not. An API would mean receiving your files, which is precisely what these tools are built to avoid — everything runs in the visitor's browser and there is no server-side image path to expose. Use sharp or a hosted service for programmatic work.

From the blog

Related reading

Longer, more practical guides from the blog.

  • Practical Guides

    How to Compress Images for a Website Without Wrecking Them

    Resize before you compress. Measured on one photograph: half the width at quality 80 produced a 16.4 KB file, while full width at quality 40 produced 20.6 KB and looked far worse. The order of operations matters more than the settings.

    8 min read

  • Image Formats

    WebP vs JPEG: Which Should You Use, and When JPEG Still Wins

    WebP produced a 27.0 KB file against MozJPEG's 41.1 KB on the same photograph at slightly higher measured fidelity — 34% smaller. It also produced a larger file than JPEG on random noise. The advantage is real and content-dependent.

    9 min read

  • Image Compression

    JPEG Quality Settings Explained: What the Number Actually Means

    Quality 80 is not 80% of anything. It is an index into a quantisation table. Measured on one photograph: dropping from 100 to 90 removes 77% of the file and 4.2 dB of fidelity; dropping from 40 to 30 removes 17% and costs almost as much.

    8 min read