What is a pre-commit hook?

In the world of software development, having a consistent codebase is crucial. That’s where pre-commit hooks come in. These powerful scripts run before each commit, ensuring that your code meets the established standards and preventing buggy and inconsistent code from making it into your project. In short, pre-commit hooks are an essential tool for maintaining a high-quality codebase.

Why use Husky?

Husky is a tool that allows you to easily add pre-commit hooks to your project. It is easy to use and works with any project. In the following, we will use the latest version of, Husky v8, which had a change of behaviour.

How to use Husky?

Install Husky

In your project root directory. Run the following command:

npm install husky --save-dev

Add pre-commit hook

In your project root directory. Run the following command: It does the following:

  • initializes the Git pre-commit hook and creates .husky/pre-commit file
  • adds a prepare script to package.json which will install the hook on every npm install / npm update
npx husky-init

The .husky/pre-commit file should look like this: You can see that the default action is npm test

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm test

Test pre-commit hook

Now, if you try to commit, you should see something like this:

git commit -m "init"

> [email protected] test
> echo "Error: no test specified" && exit 1

Error: no test specified
husky - pre-commit hook exited with code 1 (error)

Now, with that given, you are free to do define your own custom hooks. Let’s see how to do that.

Custom hooks

ESLint pre-commit hook

Let’s say you have ESLint already setup and you want to run it before committing. Before we do that, let’s add another package which will help us run ESLint specifically on the files that are being committed.

Install lint-staged

npm install lint-staged --save-dev

Add lint-staged to package.json

Adjust the file selector to your needs. In this case, we are only interested in JavaScript files.

  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
    ]
  }

Modify .husky/pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

Testing the pre-commit hook

Now, if you try to commit, you should see something like this:

git commit -m "test"                                                                                                                                                 

✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
[main 2a6aede0] test
 2 files changed, 1 insertion(+), 3 deletions(-)

Full package.json

{
  "name": "git-pre-commit-husky",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepare": "husky install"
  },
  "author": "",
  "license": "ISC",
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix"
    ]
  },
  "devDependencies": {
    "husky": "^8.0.0",
    "eslint": "^8.42.0",
    "lint-staged": "^13.2.3"
  }
}

URL to the repository: https://github.com/Ecostack/git-pre-commit-husky

Conclusion

In short, using pre-commit hooks with Husky is an easy way to enforce coding standards and improve code quality. Customizing hooks based on your project’s needs is also simple and straightforward. By utilizing pre-commit hooks, your project can maintain a clean and maintainable codebase.