We’ve all been there: you push a feature to GitHub, only to have the CI/CD pipeline fail five minutes later because of a missing semicolon or a trailing space. It’s a waste of time for you and a noise pollutant for your team. The solution is simple: move those checks from the cloud to your local machine using Git hooks.
If you’re wondering how to use husky for git hooks, you’ve come to the right place. In my experience, Husky is the gold standard for Node.js projects because it makes managing hooks effortless and shareable across a team. Instead of manually configuring the .git/hooks folder (which isn’t tracked by version control), Husky allows you to define your hooks in your package.json or a dedicated directory.
Prerequisites
Before we dive in, ensure you have the following set up in your environment:
- Node.js (LTS version recommended)
- A Git repository initialized in your project folder
- A
package.jsonfile (runnpm init -yif you don’t have one) - Basic familiarity with the terminal
Step-by-Step Guide: Implementing Husky
Step 1: Install Husky
The modern way to install Husky is using the husky-init command. This handles the installation and sets up the necessary scripts in one go.
npx husky-init && npm install
This command does three critical things: it adds husky to your devDependencies, creates a .husky/ directory in your root, and adds a prepare script to your package.json. This prepare script is vital because it ensures that every team member who runs npm install also gets Husky configured locally.
Step 2: Creating Your First Hook
By default, husky-init creates a pre-commit hook that runs npm test. Let’s customize this. Most of us want to run a linter and a formatter to ensure the code is clean. If you’re still deciding on your tooling, check out my eslint vs prettier configuration guide to get your rules sorted first.
To change the hook, open the .husky/pre-commit file and modify the command:
# .husky/pre-commit
npm run lint
npm test
Step 3: Optimizing with lint-staged
Running npm run lint on the entire project for every commit is a performance nightmare as your app grows. I always recommend pairing Husky with lint-staged. This tool ensures that only the files you’ve actually changed (the staged files) are linted.
First, install the package:
npm install --save-dev lint-staged
Now, add a lint-staged configuration to your package.json:
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"]
}
}
Finally, update your Husky pre-commit hook to trigger lint-staged instead of the full lint command:
# .husky/pre-commit
npx lint-staged
As shown in the image below, when you attempt to commit, Husky will now intercept the process, run your linters, and if any errors are found that cannot be auto-fixed, it will block the commit. This creates a “quality gate” that protects your main branch.
Pro Tips for Advanced Workflows
- Skip Hooks for Emergencies: Sometimes you need to commit a work-in-progress (WIP) without running tests. You can use the
--no-verifyflag:git commit -m "WIP" --no-verify. Use this sparingly! - Pre-Push Hooks: For heavier tasks like integration tests or security audits, use a
pre-pushhook. This prevents broken builds from reaching your github actions code quality workflow. - Commit Message Validation: You can use the
commit-msghook with a tool likecommitlintto enforce Conventional Commits (e.g.,feat: add login logic), which makes generating changelogs automatic.
Troubleshooting Common Issues
| Issue | Solution |
|---|---|
| Husky not triggering | Run git config core.hooksPath .husky to ensure Git knows where to look. |
| Permission Denied (Unix) | Run chmod +x .husky/pre-commit to make the hook executable. |
| npm install doesn’t trigger Husky | Check if "prepare": "husky install" exists in your package.json scripts. |
What’s Next?
Now that you’ve mastered how to use husky for git hooks, your local workflow is bulletproof. The next logical step is to mirror these checks in your CI environment. Local hooks are great for developer experience, but CI is the source of truth. I recommend setting up a robust pipeline to catch edge cases that local hooks might miss.
Ready to level up your productivity? Explore my other guides on automation and development tools to streamline your coding process.