mozjpeg cjpeg 3.3.1 (mozjpeg npm 8.0.0) vs libvips jpeg via sharp 0.35.5 (mozjpeg:false) on one 1920×1080 JPEG → q80. Warm medians (7 rounds after 1 warm-up): cjpeg 385 ms / 675,128 B vs libvips jpeg 31 ms / 675,714 B (~12×). Context: sharp mozjpeg:true 308 ms / 546,546 B. Fixture /workspace/bench-mozjpeg-libvips/. cjpeg timed with spawn + PPM read.
4 min read
I encoded one 1920×1080 photo at JPEG quality 80 seven times on this box: mozjpeg cjpeg 3.3.1 median 385 ms (675 KB out), libvips jpeg via sharp 0.35 median 31 ms (676 KB out) — about 12× faster at nearly the same size.
Short answer: for in-process Node pipelines, libvips jpeg was the default here. Standalone mozjpeg still fits shell scripts and imagemin-style CLI hooks. No affiliate links in this post.
| Path | Median wall | Min / Max | Output JPEG |
|---|---|---|---|
| mozjpeg cjpeg 3.3.1 q80 (from PPM) | 385 ms | 370 / 476 | 675,128 B |
| libvips jpeg via sharp q80 | 31 ms | 29 / 32 | 675,714 B |
| sharp mozjpeg q80 (context) | 308 ms | 297 / 318 | 546,546 B |
Same source photo, same box. cjpeg times include process spawn and PPM read; libvips times are in-process. Even allowing for spawn, the gap stayed roughly an order of magnitude. For sharp vs gulp imagemin-mozjpeg, see Sharp vs imagemin. For sharp vs a JS codec on resize, see Sharp vs Jimp. For SVG optimize, see SVGO vs SVGR.
Yes, when your pipeline is already a shell or imagemin plugin chain and you want mozjpeg-specific flags without taking a sharp native addon. On this Linux box, libvips jpeg returned in 31 ms median at almost the same bytes as cjpeg. If you need the smaller sharp mozjpeg output (~547 KB here), that is a different knob than plain libvips jpeg.
Treat this post as mozjpeg cjpeg vs libvips jpeg on one q80 encode, not a quality-panel shootout.
| Situation | My pick |
|---|---|
| Node CI or server with sharp already | libvips jpeg (or sharp mozjpeg if size wins) |
| Shell / Make / imagemin CLI only | mozjpeg cjpeg can stay |
| Need smallest q80 file in this lab | sharp mozjpeg |
| High-volume thumbnail farm | libvips / sharp |
| Watching asset budgets after images | Pair with size-limit vs bundlesize and SWC vs esbuild vs Babel |
| Cannot install native addons | Stay on cjpeg or WASM |
Bottom line: on one 1920 photo at q80, mozjpeg cjpeg returned in 385 ms median with a 675 KB file while libvips jpeg via sharp needed 31 ms and 676 KB. Who should not switch: teams whose only JPEG step is an existing cjpeg shell recipe and who cannot take sharp.
How this was made: I reused a 1920×1080 JPEG on the ShopperCove box, wrote a PPM for cjpeg, timed interleaved encodes against sharp libvips jpeg after a warm-up, recorded JSON medians and output bytes; the write-up was drafted with AI help and checked against that output.
Lab evidence
Hands-on on ShopperCove box 6 Oct 2026 ~00:26–00:28 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). mozjpeg npm 8.0.0 / cjpeg 3.3.1 vs sharp 0.35.5 libvips jpeg (mozjpeg:false). Fixture /workspace/bench-mozjpeg-libvips/: src-1920.jpg 1920×1080 JPEG ~981 KB; cjpeg from P6 PPM; sharp from JPEG. 1 warm-up + 7 interleaved rounds. Medians cjpeg 385 ms (370–476) / 675,128 B vs libvips jpeg 31 ms (29–32) / 675,714 B (~12×). Context sharp mozjpeg 308 ms / 546,546 B. Raw: /workspace/bench-mozjpeg-libvips/res-mozjpeg-libvips.json. Not tested: vips CLI, PNG/WebP/AVIF, trellis multipass, Windows/macOS, serverless cold starts. No affiliate.
@jsquash/jpeg 1.6.0 (Squoosh mozjpeg WASM) vs sharp 0.35.5 mozjpeg on one 1920×1080 JPEG → q80 encode from pre-decoded RGBA. Warm medians (7 rounds after 1 warm-up): Squoosh WASM 483 ms / 675,247 B vs sharp mozjpeg 291 ms / 546,546 B (~1.7×). Context: sharp decode+encode mozjpeg 303 ms; sharp libvips jpeg from raw 23 ms / 675,714 B. Fixture /workspace/bench-squoosh-sharp/. @squoosh/lib 0.5.3 fails on Node 22.
Hands-on6 Oct 20264 min read
sharp 0.35.5 vs imagemin 9.0.1 + imagemin-mozjpeg 10.0.0 on one 1920×1080 JPEG → JPEG q80 (no resize). Warm medians (7 rounds after 1 warm-up): sharp 305 ms / 546,546 B vs imagemin-mozjpeg 399 ms / 675,128 B (~1.3×). Context: sharp resize 800 q80 median 115 ms / 142,435 B. Fixture /workspace/bench-sharp-imagemin/.
Hands-on6 Oct 20264 min read
sharp 0.35.5 vs Jimp 1.6.1 on one 1920×1080 JPEG → width 800 JPEG q80. Warm medians (7 rounds after 1 warm-up): sharp 112 ms / 142,435 B vs Jimp 366 ms / 269,590 B (~3.3×). Fixture /workspace/bench-sharp-jimp/.
Hands-on6 Oct 20264 min read