Plate 36
lefthook vs husky: Should You Switch? 615ms vs 478ms
husky 9.1.7 + lint-staged 16.2.3 vs lefthook 1.13.6 on a 40-file prettier pre-commit: local-bin medians 478 ms vs 615 ms (~1.29x); npx path 651 ms vs 765 ms; install 283 ms vs 256 ms.
Aditya Challa5 min read
On a 40-file prettier pre-commit, husky 9.1.7 plus lint-staged 16.2.3 took a median 478 ms when both used local binaries, and lefthook 1.13.6 took 615 ms (~1.29x). Hook install was close: lefthook 256 ms vs husky 283 ms. With the common npx wrappers the gap stayed in husky's favor (651 ms vs 765 ms).
Short answer: do not switch to lefthook for raw speed on a single prettier hook. Stay on husky plus lint-staged if that stack already works. Move to lefthook when you want a YAML-native Go runner, monorepo-friendly parallel commands, or to drop the lint-staged Node layer. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM Linux cloud box, tested 5 Oct 2026 (about 23:20 to 23:25 IST). Shared box; variants interleaved each round.
- Fixture: two git repos with the same 40 unformatted
.jsmodules staged for commit. Task: run prettier 3.6.2--writeon those staged files. - Tools: husky 9.1.7 with lint-staged 16.2.3; lefthook 1.13.6. Node at the time of the hook runs was v22.14.0 via the Volta default on the box.
- Timing: one warmup each, then five interleaved rounds. Wall clock via
process.hrtimearound the hook command (not a fullgit commit, so empty-commit noise is out of the number). - Findings: local-bin medians 477.5 ms (husky/lint-staged) vs 614.5 ms (lefthook calling
node_modules/.bin/prettier). Install medians 282.5 ms (husky) vs 255.9 ms (lefthook). Bare prettier without any hook framework: 464 ms. - One surprise: lefthook's Go binary did not win this single-command case. Most of the wall time is prettier plus process startup; an extra runner layer still shows up at this size.
- Not tested: many parallel lefthook commands, monorepo per-package hooks, eslint on TypeScript, Windows/macOS, pre-push, commit-msg.
Is lefthook faster than husky on a prettier pre-commit?
| Variant | Median wall | Runs (ms) |
|---|---|---|
husky path: local lint-staged --allow-empty | 478 ms | 478 / 459 / 474 / 478 / 488 |
lefthook path: local lefthook + local prettier | 615 ms | 614 / 617 / 615 / 621 / 610 |
husky path: npx lint-staged --allow-empty | 651 ms | 628 / 651 / 630 / 694 / 689 |
lefthook path: npx lefthook + npx prettier | 765 ms | 758 / 750 / 765 / 787 / 884 |
Bare npx prettier --write src/*.js (no hook) | 464 ms | 457 / 468 / 468 / 464 / 463 |
No. On this 40-file fixture husky plus lint-staged was faster in both the local-binary and npx setups. Lefthook still beats a cold full Node toolchain story when you configure many parallel commands in YAML; that is not what I measured here. If your pre-commit is mostly format-on-save style work, see the dprint vs Prettier post and the Biome vs ESLint/Prettier post for the formatter choice underneath the hook.
How long does hook install take?
| Install | Median wall | Runs (ms) |
|---|---|---|
npx husky then write .husky/pre-commit | 283 ms | 277 / 283 / 344 / 348 / 265 |
npx lefthook install | 256 ms | 255 / 305 / 265 / 256 / 254 |
Almost a wash. Lefthook was about 27 ms faster to wire the git hook on this box. Neither install time should decide a migration.
Should you switch from husky to lefthook?
| Situation | My pick |
|---|---|
| Single prettier or eslint pre-commit, already on lint-staged | Stay on husky; it was faster here |
| You want YAML config and a Go runner checked into the repo | lefthook |
| Monorepo with many parallel hook commands | lefthook (not measured; that is the product pitch) |
| Team is happy and hooks finish under a second | Do not switch this quarter |
| You are choosing a linter/formatter first | Fix that before the hook runner; see oxlint vs ESLint and knip vs depcheck |
Bottom line: husky plus lint-staged won the 40-file prettier hook (478 ms vs 615 ms local binaries; 651 ms vs 765 ms with npx). lefthook install was slightly quicker (256 ms vs 283 ms). Who should not switch yet: repos whose only pain is "prettier on staged files" and who already ship husky. Who should try lefthook: teams that outgrew a one-line lint-staged config and want parallel, YAML-defined hooks.
How this was made: I built two identical 40-file git fixtures, ran interleaved hook and install timings on the ShopperCove test box, and kept the JSON; the write-up was drafted with AI help and checked against that output.
Sources
- https://github.com/typicode/husky
- https://github.com/lint-staged/lint-staged
- https://github.com/evilmartians/lefthook
- https://www.npmjs.com/package/husky
- https://www.npmjs.com/package/lefthook
- https://github.com/prettier/prettier
Related
- https://www.shoppercove.com/blog/dprint-vs-prettier
- https://www.shoppercove.com/blog/biome-vs-eslint-prettier
- https://www.shoppercove.com/blog/oxlint-vs-eslint
- https://www.shoppercove.com/blog/knip-vs-depcheck
- https://www.shoppercove.com/blog/turbo-vs-nx
- https://www.shoppercove.com/blog/madge-vs-dependency-cruiser
- https://www.shoppercove.com/blog/pnpm-vs-npm-vs-bun
- https://www.shoppercove.com/blog/c8-vs-nyc
Lab evidence
What I found running this
Hands-on on ShopperCove box 5 Oct 2026 ~23:20-23:25 IST (8 vCPU Intel Xeon / 15 GB shared Linux). Fixture: 40 unformatted .js modules staged in twin git repos. Versions: husky 9.1.7, lint-staged 16.2.3, lefthook 1.13.6, prettier 3.6.2; Node v22.14.0 during hook runs. 1 warmup + 5 interleaved rounds (hook) and 5 for install. Medians install: husky 282.5 ms (276.7/282.5/343.7/347.7/265.2); lefthook 255.9 ms (254.9/304.8/264.9/255.9/254). Hook local bins: husky lint-staged 477.5 ms (477.5/459.2/473.5/478.2/487.8); lefthook+local prettier 614.5 ms (614.4/617.1/614.5/621.1/609.9). Hook npx path: husky 650.8 ms; lefthook+npx prettier 764.6 ms; bare npx prettier 464.0 ms. Timed hook command only (not full git commit). Raw: /workspace/bench-lefthook-husky/res-lefthook-husky.json. Not tested: parallel lefthook commands, monorepo hooks, eslint/TS, Windows/macOS, pre-push. No affiliate.
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 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
Plate 94
Should You Leave Prettier? 1.59s vs 0.51s
dprint 0.60.1 vs Prettier 3.9.9 on 180 files (120 JS + 40 JSON + 20 MD, 38925 B pristine): write medians 514 ms vs 1586 ms; check 455 ms vs 1313 ms. Output 44805 vs 45285 B. All 120 JS files differed on arrow-param parentheses under these defaults.
5 Oct 2026