Hi, I'm Rodo 👋

I'm a Software Engineer

Rodolfo Guluarte Hale

Hi, I'm Rodo 👋

I'm a Software Engineer

Automating Code Quality in JavaScript with Husky and Lint-Staged

6 minutes
June 25, 2025

In JavaScript project development, maintaining code consistency and ensuring high-quality standards can be a challenge, especially in teams with multiple contributors.

Integrating automation tools into the workflow allows for the automatic execution of essential tasks such as formatting, code analysis (lint), and running tests before commits or pushes are made.

This article explores in detail how to configure Husky and Lint-Staged to reinforce code quality in your JavaScript projects.

What are Husky and Lint-Staged?

Husky is a native solution for managing Git hooks, which are scripts that run automatically on certain Git events (like before a commit or a push). Thanks to Husky, it’s possible to ensure that a series of essential checks and tasks are completed before changes are integrated into the repository.

On the other hand, Lint-Staged is a tool that allows you to run commands only on files that have been modified and are in a “staged” state. This results in a much more efficient process, as formatting and validations are applied only to the small set of affected files, instead of analyzing the entire codebase.

Why use Husky and Lint-Staged?

Using Husky and Lint-Staged brings multiple benefits to JavaScript application development:

Configuring Husky and Lint-Staged

Below is a detailed process for configuring Husky and Lint-Staged in a JavaScript environment, integrating fundamental tools like Prettier, ESLint, and Vitest.

Setting up the environment

Imagine we are working on a JavaScript project where it is essential to maintain clean and error-free code. To do this, we will configure the following scripts in the package.json file:

These commands will be integrated into our Git hooks so that, before each commit, the code is formatted, analyzed, and tested.

Installing and configuring Husky

Run the following command to install Husky as a development dependency:

npm install --save-dev husky

Initialize Husky in your repository (remember that you must have previously initialized Git in the project):

npx husky init

This command automatically adds a preparation script in the package.json and creates a .husky folder in the root of the project that will contain, among others, the pre-commit hook.

Configuring the pre-commit hook: Edit the .husky/pre-commit file to include the necessary commands. For example:

npm run format
npm run lint
npm run test

With this configuration, every time you make a commit, Husky will execute these commands. If any of them fail, the commit process will be stopped, allowing you to correct the errors before proceeding.

Installing and configuring Lint-Staged

Add Lint-Staged as a development dependency:

npm install --save-dev lint-staged

Add the following script in your package.json file to facilitate the execution of Lint-Staged:

"scripts": {
  "lint-staged": "lint-staged"
}

Create a file called .lintstagedrc.json in the root of the project and define the commands to be executed for the modified files. For example:

{
  "*.{css,scss}": ["npx prettier . --write"],
  "*.{js,jsx,ts,tsx}": [
    "npx prettier . --write",
    "eslint --fix",
    "vitest run --environment=jsdom"
  ]
}

With this configuration, Lint-Staged will apply Prettier, ESLint, and Vitest only to the JavaScript files (and their variants) that have been modified and added to the staging area.

To take advantage of Lint-Staged in the pre-commit hook, modify the .husky/pre-commit file to execute the Lint-Staged script instead of running the commands individually:

npm run lint-staged

This way, the validation process is optimized by focusing only on the changes made, saving time and resources.

Practical example with the configuration ready

Below, I leave you an example in which a change is added to the staging area, allowing us to observe in detail the step-by-step execution of each of the configured rules.

git add -A && git commit -am "Add test tutorial"
> catalitico-one-page @0.0.0 lint-staged
> lint-staged

✔ Preparing lint-staged...
⚠ Running tasks for staged files...
  ❯ .lintstagedrc.json — 1 file
    ↓ *.{css,scss} — no files
    ❯ *.{js,ts,tsx,vue} — 1 file
      ✔ npx prettier . --write
      ✖ eslint --fix [FAILED]
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...

✖ eslint --fix:

/home/andrey/Xuma/catalitico-one-page/src/components/utils/Reveal.tsx
  10:7  error  'a' is assigned a value but never used  @typescript-eslint/no-unused-vars

✖ 1 problem (1 error, 0 warnings)

husky - pre-commit script failed (code 1)

When executing git add -A && git commit -am "Add test tutorial", Husky activates the pre-commit hook.

Lint-Staged starts and processes only the files that have been modified. In this case, the process attempts to:

  1. Format the file with Prettier (npx prettier . --write), which is done correctly.
  2. Run ESLint with the automatic correction option (eslint --fix), but an error is detected in the Reveal.tsx file (a variable is assigned but never used).

Due to this error, the execution of the tasks is stopped, the state of the modified files is reverted, and the commit is canceled.

Conclusions

The integration of Husky and Lint-Staged in a JavaScript project is a highly effective strategy to ensure the quality and consistency of the code.

By automating fundamental tasks such as formatting, static analysis, and test execution, these tools allow for the early detection of errors and ensure that the code integrated into the repository complies with established standards.

Although the initial configuration may seem complex, the long-term benefits such as error reduction, a more agile development process, and greater team uniformity amply justify the investment of time and effort.

The implementation of Husky and Lint-Staged not only improves the quality of the final product but also promotes good practices and optimizes the workflow, allowing you to concentrate efforts on creating robust and scalable solutions in JavaScript.

I hope you find this guide useful and that it encourages you to incorporate these practices into your projects. Success in your developments!

Thanks for reading.