// the find
typicode/husky
Git hooks made easy 🐶 woof!
Husky is a thin wrapper around Git's native `core.hooksPath` that wires up hook scripts automatically on `npm install`. It's the de facto standard for enforcing pre-commit linting, commit message validation, and similar checks in JavaScript/TypeScript projects. At 2 kB with zero runtime dependencies, it's about as lightweight as a tool in this space can be.
The v9 rewrite dropped the over-engineered config format — hooks are now just plain shell scripts in `.husky/`, which means any developer who can read a shell script can understand and modify them without reading docs. Using `core.hooksPath` instead of symlinking into `.git/hooks` is the right call: it survives clones cleanly and works in monorepos without hacks. The ~1ms overhead is real — it's literally just a shell script invoking your linter, no Node.js bootstrap on the hot path. Cross-platform Windows support is a genuine differentiator over hand-rolled hook setups.
Hooks only run if developers have run `npm install` and the `prepare` script fired — anyone who clones and uses a non-npm workflow (Bun, Yarn PnP with `enableScripts: false`, or just `git clone` without installing) gets no hooks at all, silently. There's no mechanism to verify hooks are actually installed in CI, so you can never truly rely on them for enforcement — you still need a CI lint step. The migration from v4 to v9 is a real breaking change with a dedicated migration guide, which is painful for long-lived projects. And since hooks are just shell scripts, anything beyond a simple `npm test` call requires the developer to know POSIX shell, which is a non-obvious requirement in a JavaScript toolchain.