ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 95

  1. Blog

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/.

Aditya Challa·5 October 2026·4 min read

Hands-on
On this page
  1. What I tested
  2. How wide was the encode gap?
  3. Does imagemin ever win this call?
  4. Should you switch image libraries?
  5. Sources
  6. Related

I encoded one 1920×1080 JPEG at quality 80 seven times on this box: sharp 0.35 median 305 ms (547 KB out), imagemin-mozjpeg 10 median 399 ms (675 KB out) — about 1.3× slower and ~23% larger for the same q80 encode.

Short answer: for Node image pipelines that can load a native binding, sharp was the default here. imagemin still fits gulp-style plugin stacks that only minify already-sized assets. 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:22–00:23 IST.
  • Versions: sharp 0.35.5 (libvips / mozjpeg); imagemin 9.0.1; imagemin-mozjpeg 10.0.0; Node 22.20.0.
  • Fixture: /workspace/bench-sharp-imagemin/. Source src-1920.jpg is a 1920×1080 JPEG (~981 KB). Primary task: JPEG encode quality 80 with no resize. sharp used mozjpeg:true; imagemin used imageminMozjpeg({quality:80}) via imagemin.buffer.
  • Extra check: sharp resize width 800 + jpeg q80 (same geometry as my Sharp vs Jimp lab) for pipeline context only.
  • Timing: performance.now around each encode; 1 warm-up each, then 7 interleaved rounds. Outputs written to out/ for size checks.
  • Findings: sharp encode median 305 ms (min 298 / max 307), out 546,546 B. imagemin-mozjpeg median 399 ms (391–418), out 675,128 B. Ratio ~1.3× on wall clock. sharp resize+encode median 115 ms / 142,435 B at 800×450.
  • One surprise: at the same nominal quality 80, imagemin-mozjpeg kept ~128 KB more than sharp's mozjpeg path on this photo.
  • Not tested: PNG/WebP/AVIF, imagemin-pngquant, gulp wiring, Squoosh, concurrency, Windows or macOS, serverless cold starts.

How wide was the encode gap?

PathMedian wallMin / MaxOutput JPEG
sharp 0.35 jpeg q80 (mozjpeg)305 ms298 / 307546,546 B
imagemin-mozjpeg 10 q80399 ms391 / 418675,128 B
sharp resize 800 + jpeg q80 (context)115 ms112 / 143142,435 B

Same source buffer, same box, encode-only for the headline numbers. sharp also covers resize/crop in one chain; imagemin alone does not — that is a feature gap, not just a speed gap. For the pure resize comparison against a JS codec, see Sharp vs Jimp. For build minify cousins, see terser vs esbuild/swc minify and SWC vs esbuild vs Babel.

Does imagemin ever win this call?

Yes, when your repo is already a gulp or legacy plugin pipeline and you only minify files that are already at final dimensions. imagemin-mozjpeg dropped into that shape without a native sharp install. On this Linux box with a normal npm install, sharp was faster and smaller on the same q80 job, and it can resize in the same call.

I did not run Squoosh (@squoosh/lib); that path is a different maintenance story. Treat this post as sharp vs imagemin-mozjpeg on one JPEG q80 encode, not a full codec survey.

Should you switch image libraries?

SituationMy pick
Node CI or server that can install sharpsharp
Gulp/imagemin plugin stack, assets pre-sizedimagemin can stay
Need resize + encode in one stepsharp
High-volume thumbnail farmsharp
Watching bundle/asset budgets after imagesPair with size-limit vs bundlesize and Vite vs Parcel​
Already on Astro/Vite pipelines using sharpStay; do not add imagemin beside it

Bottom line: on one 1920 JPEG at q80, sharp returned in 305 ms median with a 547 KB file while imagemin-mozjpeg needed 399 ms and 675 KB. Who should not switch: teams locked into an imagemin gulpfile that only touches final-size assets and cannot take a native addon.

How this was made: I reused a 1920×1080 JPEG on the ShopperCove box, installed sharp and imagemin-mozjpeg, timed interleaved encode rounds 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://sharp.pixelplumbing.com/
  • https://github.com/imagemin/imagemin
  • https://github.com/imagemin/imagemin-mozjpeg
  • https://www.npmjs.com/package/sharp
  • https://www.npmjs.com/package/imagemin

Related

  • https://www.shoppercove.com/blog/sharp-vs-jimp
  • https://www.shoppercove.com/blog/size-limit-vs-bundlesize
  • https://www.shoppercove.com/blog/swc-vs-esbuild-babel
  • https://www.shoppercove.com/blog/terser-vs-esbuild-swc-minify
  • https://www.shoppercove.com/blog/vite-vs-parcel
  • https://www.shoppercove.com/blog/source-map-explorer-vs-webpack-bundle-analyzer
  • https://www.shoppercove.com/blog/lightningcss-vs-postcss
  • https://www.shoppercove.com/blog/rolldown-vs-rollup
sharpimageminjpegnode.jsperformancebenchmarkingimage-processingmozjpeg

Lab evidence

What I found running this

Hands-on on ShopperCove box 6 Oct 2026 ~00:22–00:23 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 22.20.0). sharp 0.35.5 (mozjpeg) vs imagemin 9.0.1 + imagemin-mozjpeg 10.0.0. Fixture /workspace/bench-sharp-imagemin/: src-1920.jpg 1920×1080 JPEG ~981 KB; encode JPEG q80 no resize. 1 warm-up + 7 interleaved rounds. Medians sharp 305 ms (298–307) / 546,546 B vs imagemin-mozjpeg 399 ms (391–418) / 675,128 B (~1.3×). Context resize 800 q80: sharp 115 ms / 142,435 B. Raw: /workspace/bench-sharp-imagemin/res-sharp-imagemin.json. Not tested: PNG/WebP/AVIF, pngquant, gulp, Squoosh, concurrency, Windows/macOS, serverless cold starts. No affiliate.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • 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 47

    bun test vs Vitest: 136ms vs 1.67s on 300 Tests

    bun test 1.4.2 vs Vitest 5.0.3 on 300 TypeScript tests in 60 files: warm wall medians 136 ms vs 1,673 ms (~12x); Vitest --no-isolate 765 ms (~5.6x). A 5-file vitest-API check (vi.fn, vi.mock, fake timers, spyOn, it.each, snapshot) passed 7/7 under Bun.

    5 Oct 2026

  • Plate 46

    esbuild-register vs jiti: 343ms vs 540ms Cold

    esbuild-register 3.6.0 vs jiti 2.7.0 on a 61-file TypeScript graph: cold wall medians 343 ms vs 540 ms (~1.57x); after jiti disk cache warm, 185 ms vs esbuild-register 350 ms. Same printed result 970.

    5 Oct 2026

On this page

  1. What I tested
  2. How wide was the encode gap?
  3. Does imagemin ever win this call?
  4. Should you switch image libraries?
  5. Sources
  6. Related
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove