Managing Git hooks manually can quickly become tedious and error-prone—especially in fast-moving JavaScript or Node.js projects. That’s where Husky offers a powerful advantage. It allows developers to automate Git hooks using familiar tools like npm and package.json
.
With Husky, teams can integrate pre-commit linting, testing, and formatting directly into the Git lifecycle. This ensures clean, consistent commits and catches errors early—before they hit the main branch.
This guide explains how to use Husky with npm to streamline your Git workflow, enforce standards, and reduce friction across development environments.
Husky is a tool that automates Git hooks in JavaScript and TypeScript projects. It helps enforce code standards before changes are committed or pushed. Developers use it to prevent bad code from entering a shared repository.
Git hooks are scripts that run automatically on specific Git events like pre-commit
, commit-msg
, or pre-push
. By default, they exist in .git/hooks
and require manual scripting. Husky abstracts this and allows developers to manage hooks with familiar tools like npm
and package.json
.
Husky is commonly used to run linters, formatters, tests, or validate commit messages. This ensures consistency in a codebase, especially in large or collaborative projects. Without Husky, maintaining hook logic across team members becomes error-prone and fragmented.
Git hooks are executable scripts triggered during Git lifecycle events. These include pre-commit
, prepare-commit-msg
, commit-msg
, post-commit
, pre-push
, among others. Each hook has a specific trigger and must be placed in .git/hooks
.
Hooks are not version-controlled by default. This makes them unsuitable for team workflows unless manually synchronized. For example, if one developer writes a pre-commit
hook to run ESLint, no one else on the team benefits unless the hook is manually shared.
Husky solves this by moving the hook logic into the project directory and storing it under version control. This ensures consistency across all machines using the same repository.
Husky creates a .husky/
directory in your project where all hooks live. It connects each Git hook with an executable shell script that can run any command. The setup is simple and integrates directly into your development workflow using npm scripts.
Unlike native Git hooks, Husky-managed hooks are portable. You commit them into your repository, and they work out of the box for every developer. You don’t need extra tooling or manual steps.
For example, a pre-commit
hook with Husky can run npm test
or eslint .
with just a few lines. Husky reduces friction by using shell scripts instead of Node-specific configurations, so it’s compatible with any command-line tool.
You need an active Git repository and Node.js installed. Husky supports Node.js v12.13.0 and later, but using the latest LTS version is recommended. You also need npm or yarn, depending on your project setup.
Ensure your project is already initialized with Git using git init
. Without Git, Husky won’t be able to install hooks or link them correctly.
Also, check for write permissions in the repo folder, especially in enterprise environments with locked-down permissions. Husky installs hooks directly into .git/hooks
, so OS-level restrictions can cause silent failures.
To start, install Husky as a development dependency:
npm install husky --save-dev
Then run:
npx husky install
This command creates a .husky/
directory and sets up a prepare
script. You should add this prepare
script to your package.json
so Husky is re-installed automatically after every npm install
:
"scripts": {
"prepare": "husky install"
}
Once installed, you can add hooks using the npx husky add
command. The added scripts are tracked by Git, making them consistent for the whole team.
Husky creates a separate shell script for each hook inside the .husky/
directory. You can manually edit these scripts or create them using CLI commands. Each script file is linked to a Git hook.
For example, to create a pre-commit
hook that runs tests:
npx husky add .husky/pre-commit "npm test"
This creates a .husky/pre-commit
file with an executable script. Husky automatically links it to Git’s pre-commit
lifecycle event. The command inside the file (npm test
) is executed whenever you try to commit.
You can chain multiple commands using shell syntax. For example:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint && npm run test
This allows conditional execution. The commit proceeds only if both commands succeed.
Running tools on every file can be slow. lint-staged
helps by running linters or formatters only on staged files. It’s often used with Husky for performance and precision.
First, install lint-staged
:
npm install lint-staged --save-dev
Then configure a pre-commit
hook to use it:
npx husky add .husky/pre-commit "npx lint-staged"
Define the lint-staged
config in package.json
:
"lint-staged": {
"*.js": "eslint --fix",
"*.ts": "eslint --fix"
}
Now, when you stage files and run git commit
, only those files are linted. This reduces execution time and avoids touching unrelated code.
If a hook fails (non-zero exit code), Git aborts the operation. This is intentional and prevents faulty code from progressing. For example, if npm test
fails in a pre-commit hook, the commit won’t happen.
To debug, use set -x
inside the hook script. This prints each command before execution:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
set -x
npm test
Also, make sure your hook scripts have the correct permissions. Use chmod +x
on each .husky/*
file if execution fails.
If you need to bypass hooks temporarily, use:
git commit --no-verify
But this should be used cautiously and never in CI pipelines.
To remove a hook, delete its script from .husky/
. For example:
rm .husky/pre-commit
To disable all hooks temporarily, comment out the husky install
line in the prepare
script or use Git’s native override:
HUSKY=0 git commit
To uninstall Husky entirely:
npm uninstall husky
And remove .husky/
and related scripts manually.
Version control the .husky/
directory to ensure consistent hook behavior across machines. Include it in your main branch and enforce code reviews on hook changes.
Document what each hook does in a README or a hooks.md
file. This reduces confusion and helps onboard new developers.
Make sure all hook scripts are compatible with Unix and Windows shells. Avoid OS-specific commands or use cross-platform tools like cross-env
.
Set executable permissions in Git to avoid silent failures on clone:
git update-index --add --chmod=+x .husky/*
One frequent mistake is forgetting to run npx husky install
after installation. This breaks the link between Git and the .husky/
directory.
Another issue is omitting the prepare
script. Without it, Husky won’t re-install hooks on npm install
, especially on CI environments.
Also, some developers forget that Husky scripts are shell scripts. This causes syntax errors if you write Node.js-style code instead of shell commands.
Finally, permissions issues are common on Windows and CI environments. Always verify file execution rights and avoid relying on global settings.
In CI/CD pipelines, hooks aren’t triggered automatically. If you want hooks to run in CI, you must call them manually in your pipeline scripts.
For example, in a GitHub Actions workflow:
- name: Run Pre-commit Hook
run: .husky/pre-commit
Also ensure that the .husky/
directory is executable and not ignored during CI builds. Add explicit chmod +x
steps if needed.
In some setups, you might want to bypass hooks to speed up deployments:
HUSKY_SKIP_HOOKS=1 git push
This is useful for controlled automation, but shouldn’t be standard.
Husky v5+ changed its architecture. It no longer uses husky.config.js
or modifies .git/hooks
directly. Instead, it uses a .husky/
directory and shell scripts.
To migrate:
npm uninstall husky
husky.config.js
or old hook filesnpm install husky --save-dev
npx husky install
npx husky add
Avoid manually editing .git/hooks
—the new system maintains better isolation and control.
Tool | Hook Type Support | Config Format | Language | Version Controlled | Ease of Use |
---|---|---|---|---|---|
Husky | All Git hooks | Shell + CLI | Any | ✅ | High |
Lefthook | All Git hooks | YAML | Any | ✅ | Medium |
Pre-commit | Python-focused | YAML | Mostly Python | ✅ | Low (for JS) |
Simple-git-hooks | Pre-commit only | package.json | JavaScript | ✅ | High |
Husky is preferred in JavaScript/TypeScript environments due to tight npm integration and simplicity.
Frontend teams often use Husky to run eslint
and prettier
on pre-commit
. This ensures all staged code follows style guides.
Backend teams integrate Husky with test runners like Jest to prevent buggy commits. A failing test cancels the commit operation.
Monorepo setups use Husky in combination with tools like Lerna or Nx. It ensures that only affected packages are validated on each commit or push, improving performance and maintaining consistency.
Using Husky with npm transforms how developers handle Git hooks. It enables consistent JavaScript Git workflows by automating essential tasks like linting, testing, and formatting during commit or push events.
By version-controlling hooks, teams reduce manual setup and avoid configuration drift. Whether you’re maintaining a large codebase or contributing to a team project, managing Git hooks with Husky ensures code quality and speeds up development.
With minimal setup and strong community support, Husky remains one of the most efficient tools to automate Git hooks in Node.js projects.
MiniMax-M1 is a new open-weight large language model (456 B parameters, ~46 B active) built with hybrid…
Git hooks help teams enforce code quality by automating checks at key stages like commits…
Choosing the right Git hooks manager directly impacts code quality, developer experience, and CI/CD performance.…
We evaluated the performance of Llama 3.1 vs GPT-4 models on over 150 benchmark datasets…
The manufacturing industry is undergoing a significant transformation with the advent of Industrial IoT Solutions.…
If you're reading this, you must have heard the buzz about ChatGPT and its incredible…