Husky Git Hooks: Setup, pre-commit & commit-msg Automation
Husky makes Git hooks easy. Instead of manually managing scripts in .git/hooks (which are not committed to your repo), Husky stores hooks in .husky/, versions them with your code, and installs them automatically for every developer via the npm prepare script. This guide covers the full setup: lint-staged, Commitlint, and Husky v9 changes.
What Are Git Hooks and Why Use Husky?
Git hooks are shell scripts that Git runs automatically at specific points in the commit workflow — before a commit is recorded (pre-commit), after the message is entered (commit-msg), before a push (pre-push). The problem with native hooks is they live in .git/hooks, which is not tracked by Git, so every developer must install them manually.
Husky solves this by storing hooks in the .husky/ directory (tracked by Git) and using the npm prepare lifecycle script to run husky on every npm install. New developers get working hooks automatically after cloning the repo.
Installation (Husky v9)
npm install --save-dev husky
npx husky init
# Creates .husky/pre-commit and adds "prepare": "husky" to package.json
# .husky/pre-commit is now a plain shell script:
cat .husky/pre-commit
# npm test ← replace with your command pre-commit Hook with lint-staged
Running ESLint on the entire codebase before every commit is slow. lint-staged solves this by running linters only on files that are staged for commit:
npm install --save-dev lint-staged # .husky/pre-commit
npx lint-staged // package.json
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,md}": "prettier --write"
}
} commit-msg Hook with Commitlint
Commitlint validates that your commit messages follow the Conventional Commits format (feat:, fix:, chore:, etc.):
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "export default { extends: ['@commitlint/config-conventional'] }" > commitlint.config.js # .husky/commit-msg
npx --no -- commitlint --edit $1 Husky v9 Changes from v8
| Feature | v8 | v9 |
|---|---|---|
| Init command | husky install | husky init |
| Hook format | Required #!/bin/sh + source | Plain shell — Husky injects header |
| Skip in CI | is-ci package or HUSKY=0 | HUSKY=0 only |
| Config file | .huskyrc supported | No .huskyrc — scripts only |
Bypassing Hooks
# Skip hooks for a single commit (use sparingly):
git commit --no-verify -m "wip: skip hooks"
# Disable Husky entirely in CI environments:
HUSKY=0 npm ci Husky vs Lefthook vs pre-commit
| Tool | Language | Best For | Parallel Execution |
|---|---|---|---|
| Husky | Node.js | JS/TS projects | Via lint-staged |
| Lefthook | Go binary | Polyglot monorepos | Built-in |
| pre-commit | Python | Python projects | Limited |
Related Products
on GumroadDeveloper Productivity Bundle
Stop rebuilding the same setup every project. 51 VSCode snippets, 40 Git aliases, 5 Docker Compose stacks, 5 GitHub Actions workflows, 5 README templates, and a dotfiles kit. Set up a professional dev environment in under an hour.
Buy on Gumroad →AI Prompt Engineering Toolkit
58 structured prompt templates for Claude, ChatGPT, and Gemini — organized by use case. Code Review, Debugging, Documentation, Architecture, and 10 model-specific tips. Stop writing prompts from scratch.
Buy on Gumroad →Developer Cheat Sheet Bundle
10 print-ready cheat sheets for the tools developers use every day: Git, Docker, Linux CLI, SQL, Regex, HTTP Status codes, VS Code shortcuts, Bash scripting, jq/JSON, and Markdown.
Buy on Gumroad →You Might Also Need
JSON Formatter & Validator
Format, beautify, and validate JSON online. Paste your JSON to instantly pretty-print it with 2-space, 4-space, or tab indentation. Minify JSON too. Free, runs in your browser.
Open free tool →
Regex Tester
Free regex tester. Test regular expressions against multiple strings with expected match/no-match assertions — see instant pass/fail results. Built-in presets for email, URL, IPv4, and phone. Pro: unl
Open free tool →
Base64 Encoder & Decoder
Free Base64 Encoder & Decoder. Convert text, images, and any file to Base64 and back. Supports URL-safe Base64, image data URIs, and file download from Base64. Runs 100% in your browser — no data sent
Open free tool →
More Free Tools
Related Articles
curl 深度使用手冊:API 測試從入門到進階
curl 是每位開發者必備的 CLI 工具。本文涵蓋 GET/POST/PUT/DELETE 請求、認證、header 設定、檔案上傳、除錯技巧,以及 REST API 測試的完整實戰範例。
Best AI Code Review Tools 2026: CodeRabbit, Sourcery, DeepCode & Bito Compared
Compare top AI code review tools for 2026: CodeRabbit, Sourcery, DeepCode, and Bito. Features, pricing, GitHub/GitLab integration, and choosing the right tool for your team.
AI Code Review Tools 2026: GitHub Copilot, CodeRabbit, Qodo Merge Ranked
Compare AI code review tools for 2026: GitHub Copilot code review, CodeRabbit, Qodo Merge, Sourcery, and PR-Agent. Pricing, accuracy, and GitHub integration.
AI Coding Tools Comparison 2026: GitHub Copilot vs Cursor vs Windsurf vs Cline
Comprehensive comparison of the best AI coding tools in 2026: GitHub Copilot, Cursor, Windsurf, and Cline. Pricing, features, model support, and real-world benchmarks.
AI Pair Programming in 2026: GitHub Copilot vs Cursor vs Claude Code
Master AI pair programming in 2026. Compare GitHub Copilot, Cursor, and Claude Code for autocomplete, chat, and agentic workflows. Includes setup guides and productivity tips.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →Frequently Asked Questions
How do I set up Husky with lint-staged and ESLint?▼
Install the packages: npm install --save-dev husky lint-staged eslint. Run npx husky init to create the .husky directory and add a prepare script. Edit .husky/pre-commit to contain: npx lint-staged. In package.json, add a lint-staged key: { '*.{js,ts,tsx}': ['eslint --fix', 'git add'] }. Now every commit automatically lints and auto-fixes staged files before the commit is recorded.
What changed in Husky v9?▼
Husky v9 (released 2024) dropped the .huskyrc config file in favour of placing hook scripts directly in the .husky/ directory as plain shell scripts. The husky install command was replaced by husky init. Shell scripts no longer need #!/bin/sh at the top — Husky injects a source file automatically. The husky.sh helper was removed; if you need to skip hooks in CI, set HUSKY=0 as an environment variable.
How do I bypass Husky hooks with --no-verify?▼
Run git commit --no-verify (or the short form -n) to skip all client-side hooks including pre-commit and commit-msg. This is intentionally an escape hatch, not a standard workflow. In CI pipelines where Husky should not run at all, set the environment variable HUSKY=0 — Husky reads this flag and skips hook installation entirely, which is cleaner than --no-verify.
How do I use Husky in a monorepo?▼
Place Husky in the root package.json of the monorepo. Run npx husky init from the root. Because .git is at the root, all hooks fire regardless of which workspace triggered the commit. Use lint-staged with workspace-aware glob patterns like packages/*/src/**/*.ts. For per-package linting you can use the --cwd flag in lint-staged commands, or configure individual commands per glob in lint-staged config.
What is the difference between Husky and Lefthook?▼
Husky is the most popular choice: minimal, widely documented, and integrates with npm prepare scripts automatically. Lefthook is a Go binary with no Node.js dependency, making it faster on large repos and suitable for polyglot monorepos (Python/Ruby/Go). Lefthook has built-in parallel execution across hook commands and a single YAML config file. If your team is Node-only, Husky is the simpler default. If you need cross-language hooks or raw speed, Lefthook is worth evaluating.
How do I add a commit-msg hook for Commitlint?▼
After installing @commitlint/cli and @commitlint/config-conventional, create .husky/commit-msg with the content: npx --no -- commitlint --edit $1. The $1 argument is the path to the temporary commit message file that Git passes to the hook. Commitlint reads that file and validates the message against your configured rules. If validation fails, Husky exits non-zero and the commit is rejected.