Plate 26
Squoosh vs Sharp: 483ms vs 291ms Encode
@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.
Aditya Challa4 min read
I encoded one 1920×1080 photo at JPEG quality 80 seven times on this box: Squoosh mozjpeg WASM (@jsquash/jpeg 1.6) median 483 ms (675 KB out), sharp 0.35 mozjpeg from the same raw RGBA median 291 ms (547 KB out) — about 1.7× faster and ~19% smaller.
Short answer: for Node pipelines that can load a native binding, sharp won this encode. Squoosh WASM still fits browser or edge runtimes that refuse native addons. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM shared Linux cloud box, tested 6 Oct 2026 about 00:26–00:28 IST.
- Versions: @jsquash/jpeg 1.6.0 (Squoosh mozjpeg WASM encoder); sharp 0.35.5; Node 22.20.0. @squoosh/lib 0.5.3 installed but throws on Node 22 (navigator property), so I drove the same Squoosh codec through @jsquash/jpeg with the WASM binary preloaded.
- Fixture: /workspace/bench-squoosh-sharp/. Source src-1920.jpg is a 1920×1080 JPEG (~981 KB). Primary task: encode JPEG quality 80 from pre-decoded RGBA (encode-only wall times). Context: sharp decode+encode from the JPEG buffer with mozjpeg true/false.
- Timing: performance.now around each encode; 1 warm-up each, then 7 interleaved rounds. Outputs written to out/ for size checks.
- Findings: Squoosh WASM encode median 483 ms (449–510), out 675,247 B. sharp mozjpeg from raw median 291 ms (290–313), out 546,546 B. sharp decode+encode mozjpeg median 303 ms / 546,546 B. sharp libvips jpeg (mozjpeg false) from raw median 23 ms / 675,714 B.
- One surprise: @squoosh/lib is dead on current Node; the maintained path is @jsquash/* with manual WASM init.
- Not tested: browser Squoosh UI, WebP/AVIF, worker pools, Cloudflare Workers, Windows or macOS, serverless cold starts.
How wide was the encode gap?
| Path | Median wall | Min / Max | Output JPEG |
|---|---|---|---|
| Squoosh WASM (@jsquash/jpeg) q80 encode-only | 483 ms | 449 / 510 | 675,247 B |
| sharp 0.35 mozjpeg from raw RGBA q80 | 291 ms | 290 / 313 | 546,546 B |
| sharp mozjpeg decode+encode from JPEG (context) | 303 ms | 297 / 355 | 546,546 B |
| sharp libvips jpeg from raw (context) | 23 ms | 22 / 29 | 675,714 B |
Same 1920×1080 source, same box. Headline numbers are encode-only from identical RGBA. sharp still finished faster than Squoosh WASM and wrote a smaller q80 file. For resize-first pipelines, see Sharp vs Jimp. For gulp-plugin minify, see Sharp vs imagemin. For build minify cousins, see terser vs esbuild/swc minify.
Does Squoosh ever win this call?
Yes, when you cannot ship a native sharp binary: browser tabs, some edge runtimes, or locked-down CI images. @jsquash/jpeg still needs a WASM init step on Node 22. On this Linux box with a normal sharp install, sharp mozjpeg was the default.
Treat this post as Squoosh mozjpeg WASM vs sharp mozjpeg on one JPEG q80 encode, not a full codec survey. libvips jpeg (mozjpeg false) was far faster (~23 ms) at a larger file — that trade-off belongs in a separate call.
Should you switch image libraries?
| Situation | My pick |
|---|---|
| Node CI or server that can install sharp | sharp |
| Browser or no-native-addon runtime | Squoosh / <br/>jsquash |
| Need smaller q80 JPEGs in Node | sharp mozjpeg |
| Need resize + encode in one step | sharp |
| Watching asset budgets after images | Pair with size-limit vs bundlesize and Vite vs Parcel |
| Already on Astro/Vite using sharp | Stay; do not add Squoosh beside it |
Bottom line: on one 1920 photo at q80, Squoosh WASM returned in 483 ms median with a 675 KB file while sharp mozjpeg from the same raw needed 291 ms and 547 KB. Who should not switch: teams stuck without native addons who already ship in the browser.
How this was made: I reused a 1920×1080 JPEG on the ShopperCove box, preloaded Squoosh mozjpeg WASM via @jsquash/jpeg, timed interleaved encode rounds against sharp after a warm-up, recorded JSON medians and output bytes; the write-up was drafted with AI help and checked against that output.
Sources
- https://github.com/GoogleChromeLabs/squoosh
- https://github.com/jamsinclair/jSquash
- https://www.npmjs.com/package/@jsquash/jpeg
- https://sharp.pixelplumbing.com/
- https://www.npmjs.com/package/sharp
Related
- https://www.shoppercove.com/blog/sharp-vs-jimp
- https://www.shoppercove.com/blog/sharp-vs-imagemin
- https://www.shoppercove.com/blog/size-limit-vs-bundlesize
- https://www.shoppercove.com/blog/terser-vs-esbuild-swc-minify
- https://www.shoppercove.com/blog/vite-vs-parcel
- https://www.shoppercove.com/blog/swc-vs-esbuild-babel
- https://www.shoppercove.com/blog/svgo-vs-svgr
- https://www.shoppercove.com/blog/source-map-explorer-vs-webpack-bundle-analyzer
Lab evidence
What I found running this
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). @jsquash/jpeg 1.6.0 (Squoosh mozjpeg WASM; @squoosh/lib 0.5.3 fails on Node 22) vs sharp 0.35.5. Fixture /workspace/bench-squoosh-sharp/: src-1920.jpg 1920×1080 JPEG ~981 KB; encode JPEG q80 from pre-decoded RGBA. 1 warm-up + 7 interleaved rounds. Medians Squoosh WASM 483 ms (449–510) / 675,247 B vs sharp mozjpeg from raw 291 ms (290–313) / 546,546 B (~1.7×). Context sharp decode+encode mozjpeg 303 ms; sharp libvips jpeg from raw 23 ms / 675,714 B. Raw: /workspace/bench-squoosh-sharp/res-squoosh-sharp.json. Not tested: browser Squoosh UI, WebP/AVIF, workers, Cloudflare Workers, Windows/macOS, serverless cold starts. No affiliate.
Related links
Plate 95
Sharp vs imagemin: 305ms vs 399ms Encode
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/.
5 Oct 2026
Plate 88
Sharp vs Jimp: 112ms vs 366ms Resize
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/.
5 Oct 2026
Plate 73
volta vs fnm: Should You Switch? 14ms vs 17ms
volta 2.0.2 vs fnm 1.39.0 switching Node 20.19.2 ↔ 22.14.0: session A-then-B median 13.9 ms vs 17.0 ms; steady node -v 7.4 ms vs 6.4 ms (direct 4.7 ms).
5 Oct 2026