Introduction
In team development, simple mistakes like committing code with syntax errors or bad formatting are common. These issues can break the CI build or lead to messy formatting wars during code reviews.
Instead of relying on developer vigilance to enforce guidelines, you can automate these checks.
By combining Git Hooks with Husky, you can automatically trigger linters (ESLint), formatters (Prettier), and unit tests (Jest) before any commit or push is finalized. This guide walks you through setting up this workflow.
1. What are Git Hooks and Husky?
Git Hooks are scripts that run automatically whenever a key event (such as commit, push, or merge) occurs in a Git repository.
By default, these scripts live inside the .git/hooks/ directory. However, since the .git/ folder is excluded from version control (.gitignore), sharing these hooks across a team has historically been difficult.
Husky solves this problem by exposing Git Hooks to a project-level folder (e.g., .husky/). This allows team members to check hooks into Git and synchronize configurations automatically via npm packages.
2. Basic Husky Setup Steps
Run the following commands in your project repository:
Step 1: Install and Initialize
Use the husky-init CLI tool to install Husky and configure the initial directories:
# Initialize Husky configurations
npx husky-init && npm install
This command makes three modifications:
- Adds
huskyto yourdevDependenciesinpackage.json. - Adds a
"prepare": "husky"script topackage.json(which automatically installs hooks on other machines duringnpm install). - Generates a
.husky/directory at the project root along with a defaultpre-commithook file.
Step 2: Configure the Pre-Commit Hook
Open the generated .husky/pre-commit script. By default, it runs npm test. Update this command to run your linter:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Run linter and abort commit if it returns an error code
npm run lint
Now, whenever you run git commit, Husky runs npm run lint. If ESLint detects errors, the commit process is aborted, keeping broken code out of your repository.
3. Optimizing Speed with lint-staged
By default, running linters on the entire project during every commit can make the process slow as the codebase grows.
To optimize performance, use lint-staged.
This tool isolates checks so they run only on files currently staged in Git (the files you modified).
Installation and Setup
Install the Package:
npm install --save-dev lint-stagedAdd Configuration to
package.json: Define which files to target and which commands to run:{ "lint-staged": { "*.{js,ts,jsx,tsx}": [ "eslint --fix", "prettier --write" ], "*.css": [ "stylelint --fix", "prettier --write" ] } }Update the Pre-Commit Hook: Modify
.husky/pre-committo triggerlint-staged:#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" npx lint-staged
With this configuration, only your modified files are formatted and linted. This keeps the pre-commit check fast while ensuring committed code remains clean.
Conclusion
Combining Husky with lint-staged automates code quality checks, saving time during code reviews and preventing broken builds.
- Manage Git Hooks at the project level using Husky.
- Auto-configure hook installations via the package lifecycle script (
prepare). - Keep checks fast by target-scanning only staged files with
lint-staged.
Introduce Husky early in your project to keep your codebase consistent and clean.
