Squoosh CLI, imagemin, sharp, or PiPic: the 2026 image-CLI check-up
Ask around for a way to compress images from the terminal and you get the same
few answers every time: Squoosh's CLI, imagemin, sharp, or a single-format
encoder like pngquant. Most of that advice dates from 2023 or earlier. So we
spent an afternoon checking it — 7 August 2026, one ordinary laptop, macOS on
Apple Silicon, Node 22.14, the current LTS. We installed everything fresh and
ran it all over one small test folder: a PNG, a JPEG, a JPEG that had already
been optimised once, and twelve bytes of plain text renamed to broken.jpg.
Real image folders always have something weird in them.
Before running anything, the npm registry's own timestamps already tell you a lot:
@squoosh/cli 0.7.3 Jan 2023 "no longer maintained" imagemin 9.0.1 Mar 2025 imagemin-cli 8.0.0 May 2024 imagemin-mozjpeg 10.0.0 Dec 2021 imagemin-webp 8.0.0 Jan 2023 sharp 0.35.3 Jul 2026 sharp-cli 5.2.0 Jun 2025
Squoosh CLI crashed before touching the first image
We started with @squoosh/cli, because it's the one people recommend most.
It's the command-line cousin of Squoosh, the web app from Google — the web app
is great and still maintained. The CLI is not. Its last release was January
2023, and its readme says so itself: "Project no longer maintained."
The install works. The command starts. Then you ask it to compress something,
and it dies on the spot — its WebAssembly loader tries to fetch() a local
file path, and today's Node refuses:
code: 'ERR_INVALID_URL', input: '…/@squoosh/lib/build/imagequant_node-a4aafbae.wasm' — exit 1
We tried the JPEG path too. Same crash, same spot. Install this tool today and it cannot compress a single image. Tutorials still recommend it, and models trained on those tutorials recommend it too. Nobody has corrected the advice, because nobody is home.
imagemin did the job, then lied about the text file
imagemin made a better first impression. The core package had a release in March 2025, and on our real images it simply worked — three files in, "3 images minified", done.
Two things bothered us along the way. First, the install. Four packages, five
deprecation warnings, and npm audit found 37 vulnerabilities in the
brand-new project — 1 of them critical. The reason isn't hard to find: the
actual compression lives in per-format plugins, and the plugins are old. The
JPEG one last shipped in December 2021, WebP in January 2023, and AVIF has no
first-party plugin at all.
Second, the fake file:
- Minifying images 1 image minified — exit 0
It copied the twelve bytes of text into the output folder, untouched, and called it a minified image. Exit 0. You'd catch that with your eyes. A script wouldn't. An agent reading "1 image minified, exit 0" reports success and moves on to the next task.
Nothing is wrong with sharp — that's the trap
sharp itself is in great shape. It shipped a release in July 2026, it has carried image work on npm for a decade, and on maintenance it beats everything else here without trying.
But sharp doesn't compress folders. It's a library; the script is on you. So we wrote the script people actually write — a few lines, default settings — and ran it:
photo.jpg 88556 -> 38879 smaller photo-optimized.jpg 26659 -> 32050 LARGER — exit 0
The fresh JPEG compressed nicely. The already-optimised one came back 20% larger, and our script saved it anyway, because we never told it not to. That's not a bug in sharp. Quality numbers, which files to skip, what to do when the output grows, how to report results — sharp leaves all of it to whoever writes the script, and whoever writes the script is usually you at six in the evening, or your agent. We described that improvised script in Give your coding agent an image compressor; this time we watched it fail in person.
One number goes against us
Worth saying out loud: at default settings, imagemin's mozjpeg produced the smallest JPEG of the day — 26,659 bytes to pipic's 31,774. Default quality levels differ from tool to tool, so byte counts alone settle nothing; you'd need a quality comparison, and we didn't do one. This test is about behaviour, not compression ratios. But we're not going to hide the number that doesn't flatter us.
While we're being fair: the classic single-format encoders — pngquant,
oxipng, cjpeg, cwebp, avifenc — are solid, and they're what everything
above wraps anyway. If you live in one format, use them happily (for AVIF,
the AVIF page covers when it's worth switching). Four
formats, though, means four installs, four flag dialects, and a wrapper script
that's now yours to maintain.
The same folder through pipic
We gave the pipic CLI the identical directory, corrupt file included:
$ pipic ./img -o ./out --json # paths shortened
{"file":"…/img/broken.jpg","status":"error","before":12,"after":0,"saved":0,"error":"UPSTREAM_ERROR: Compression service error"}
{"file":"…/img/icon.png","status":"ok","before":13897,"after":7449,"saved":6448}
{"file":"…/img/photo-optimized.jpg","status":"skipped","before":26659,"after":26659,"saved":0,"error":"not smaller — copied as-is"}
{"file":"…/img/photo.jpg","status":"ok","before":88556,"after":31774,"saved":56782}
{"file":"…/img/photo.png","status":"ok","before":302850,"after":104288,"saved":198562}
— exit 1
Check it against the failures above, one by one. The text file comes back as
an error with a reason, and the whole run exits 1, so a script knows
something went wrong. The already-optimised JPEG is skipped and kept as-is,
reason included, instead of quietly growing 20%. And every image gets its own
line of JSON with real before/after byte counts, which a script can branch on
directly.
The trade-off is real, so here it is plainly. Every other tool in this post runs on your machine. pipic is a service: files upload, get compressed in memory, and are deleted right away — never stored — but they do leave your computer. The CLI needs an account, with 100 images a month free and 5,000 for $9 on Pro. The web compressor stays free, unlimited and account-free regardless. And if your rule is "images never leave this machine", use the local tools — that rule outranks everything else in this post.
What the account buys you is the other side of each finding above: no wasm loader left to rot, no plugin kit to assemble, no quality decisions to improvise, and output your automation can actually rely on.
We also ran a separate benchmark with 12 licensed inputs across PNG, JPEG, WebP, and AVIF. Its method, all 72 raw runs, medians, retained failure, and visual checks are public. That dataset compares PiPic Agent CLI 1.0.6 with sharp 0.35.3. The folder test above examines operational behavior and makes no compression-ratio ranking.
Run the folder test yourself
The whole method fits in an afternoon, and you don't have to trust our numbers. First check whether anyone's home:
npm view @squoosh/cli time.modified
Then make a folder with one already-optimised image and one corrupt file in it, and run your candidate tool over it. Clean images compress fine everywhere; they won't tell you a thing. The weird files are where a tool shows you its judgement — and every folder eventually has weird files.