
🛠️ Automating Quality Checks in Your Node.js Project with Husky and Git Hooks
Maintaining code quality and consistency in a team environment is crucial. Git hooks allow you to automate checks and tasks at different stages of your Git workflow. In Node.js projects, Husky makes managing these hooks simple and reliable.
In this post, we'll cover how to set up and use Git hooks like pre-commit
, commit-msg
, and pre-push
using Husky. We'll integrate tools like lint-staged, commitlint, npm test, and secret detection to ensure a clean and secure codebase.
Why Use Git Hooks?
Git hooks are scripts triggered by certain Git events (e.g., committing or pushing). They are ideal for automating:
- Code formatting and linting
- Running unit tests before a push
- Validating commit messages
- Detecting secrets before committing
Setting Up Husky in a Node.js Project
First, install the required packages:
npm install husky -D
Initialize Husky:
npx husky install
Enable Husky in your project:
// package.json
{
"scripts": {
"prepare": "husky"
}
}
This ensures Husky is set up after npm install
.
Setting Up Git Hooks
1. Commit Message Validation (commit-msg
)
Install commitlint and config-conventional:
npm install commitlint @commitlint/config-conventional -D
Add a script into your package.json:
"commitlint": "commitlint --edit",
Create a commitlint configuration:
// commitlint.config.js
module.exports = { extends: ["@commitlint/config-conventional"] };
Enforce conventional commits messages using commitlint
.
npx husky add .husky/commit-msg 'npm run commitlint "$1"'
2. Pre-commit Hook (pre-commit
)
Install lint-staged:
npm install lint-staged -D
For the porpouse of this post, I will show some of my favorite setups, using eslint and prettier, but fell free to use whatever you want:
npm install eslint prettier eslint-config-prettier eslint-plugin-prettier
Don't forget to configure your .prettierrc and .eslintrc.js files. The links shows some examples of setups for a nestjs API.
Configure .lintstagedrc
:
{
"src/**/*.+(js|json|ts|tsx)": ["eslint"],
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": ["prettier --write"]
}
npx husky add .husky/pre-commit 'npm run lint-staged'
Done, you are good to go! But if I say to you that this could become even better? Lets add also detect-secrets to our pre-commit stage, to prevent us to push sensitive data by accident to the github repository:
For this step you will need python installed, you can either intall detect secrets globally or create a ocal environment with *virtual-env. It's your choice. For this example I will install it globally, as I always use this configuration in every non-python repository:
python3 -m pip install detect-secrets
Create a baseline to your repo. This file needs to be commit into your repository:
```bash
# in this example I am telling detect-secrets to ignore lock.json
detect-secrets scan --update .secrets.baseline --exclude-files package-lock.json
This scans the repo and stores known secrets in a baseline file to avoid false positives.
To run the scan agains't your codebase in search of possible secret leaks:
detect-secrets audit .secrets.baseline
Now let's change our ./husky/pre-commit file to run detect secrets toghether with lint-staged:
npm run lint-staged && detect-secrets audit .secrets.baseline
that is it!
3. Pre-push Hook (pre-push
)
Now, this one it's a controversial, some people says that, running tests on every push can slow down your proccess. I think if you have it already configured into your CI/CD pipeline you can let this aside, but on any case, it's an option that you can try it to ensure that tests pass before code is pushed:
npx husky add .husky/pre-push 'npm test'
Summary of Recommended Hooks
Hook | Purpose | Tooling |
---|---|---|
commit-msg |
Validate commit messages | commitlint |
pre-commit |
Lint and format code, scan for secrets | lint-staged , detect-secrets |
pre-push |
Run tests before allowing code push | npm test |
Final Thoughts
By combining Husky with tools like lint-staged
, commitlint
, and detect-secrets
, you can enforce consistent quality checks directly into your Git workflow. This prevents bad commits, broken code, or sensitive data from reaching production.
Automating these steps helps teams enforce discipline and reduces the cost of fixing mistakes later in the CI/CD pipeline.