Configure Pre‑Commit Hooks to Auto‑Format and Lint JavaScript/TypeScript

User avatar placeholder
Written by Tamzid Ahmed

September 6, 2026

To ensure each commit is clean, you can Configure pre‑commit hooks to format and lint JS/TS automatically, catching style problems before they enter the codebase and keeping your repository consistently formatted.

Configure pre‑commit hooks to format and lint JS/TS

Pre‑commit hooks are scripts that Git runs automatically before a commit is created. They let you validate or modify code as part of the commit workflow, providing a built‑in quality gate that runs on every developer’s machine.

Why Automate Formatting and Linting?

Manual formatting leads to inconsistent style and wasted time during code reviews. By automating both formatting (e.g., Prettier) and linting (e.g., ESLint), you enforce a single, project‑wide code style, catch bugs early, and reduce debates over trivial differences.

Choosing the Right Tools

For JavaScript and TypeScript projects, the most common combination is Husky for Git hook management, lint‑staged to run commands only on staged files, Prettier for opinionated formatting, and ESLint for linting. All four are open‑source, widely adopted, and integrate smoothly with Node.js build pipelines.

Performance and Cache Considerations

Running Prettier and ESLint on every file can be costly in large repositories. lint‑staged mitigates this by executing the commands only on the files that are staged for commit, dramatically reducing execution time. Additionally, you can enable caching in ESLint to avoid re‑linting files that haven’t changed, further improving speed.

Step‑by‑Step Setup

Follow these steps to add a pre‑commit hook that runs Prettier and ESLint on every commit:

  1. Install the required packages as dev dependencies: npm install --save-dev husky lint‑staged prettier eslint.
  2. Initialize Husky in your project: npx husky install.
  3. Add a .husky/pre-commit script that runs lint‑staged.
  4. Configure lint‑staged in package.json to target *.{js,ts,jsx,tsx} files with Prettier and ESLint.
  5. Commit a file to verify that formatting and linting run automatically.

Make sure the .husky/pre-commit script is executable; you can run chmod +x .husky/pre-commit to set the correct permissions.

Configuring Prettier

Create a .prettierrc file at the project root with your preferred options, for example:

  • Use single quotes.
  • Enable trailing commas where valid.
  • Set the tab width to 2 spaces.

Prettier reads this configuration automatically, so no additional setup is needed in the hook script.

Configuring ESLint

Generate an ESLint configuration with npx eslint --init and choose the recommended style for JavaScript/TypeScript. Then extend it with plugin:prettier/recommended to let ESLint delegate formatting to Prettier.

Sample .eslintrc.js snippet:

module.exports = {
  root: true,
  env: { node: true, es2021: true },
  extends: ['eslint:recommended', 'plugin:prettier/recommended'],
  parserOptions: { ecmaVersion: 2021, sourceType: 'module' },
};

This configuration ensures that ESLint runs linting and also enforces Prettier’s formatting rules.

Linking the Hook to Git

After Husky is installed, the .husky/pre-commit file should contain something like:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh";

Add the actual formatting and linting commands, for example:

npm run format && npm run lint

Make it executable with chmod +x .husky/pre-commit. From this point forward, every git commit will invoke Prettier and ESLint on all staged files.

Common Pitfalls & Troubleshooting

Here are three frequent issues and how to resolve them:

  • Hooks not running: Ensure the script file is executable and that Husky is properly installed.
  • Formatter fails on TypeScript files: Verify that Prettier supports TypeScript (it does via @typescript-eslint/parser) and that your .prettierrc is in the correct location.
  • Performance slowdown: Run Prettier and ESLint only on staged files using lint‑staged to avoid processing the entire project on each commit.

Integrating with Continuous Integration

Even with a local pre‑commit hook, it’s wise to enforce the same checks in CI. Most CI services allow you to run npm run format -- --check and npm run lint as separate steps. If they fail, the build stops, ensuring that no unformatted code ever reaches the main branch.

Choosing Between Prettier and Standard Formats

Prettier enforces a strict style, which some teams love for its predictability. Others prefer a more flexible approach using eslint alone or a custom formatter like prettier-plugin-tailwindcss. Consider your team’s preferences and the existing codebase when deciding which toolset to adopt.

Testing Your Hook

Just like any piece of code, your hook can be tested. Write a simple unit test that stages a deliberately malformed file, runs the commit command, and asserts that the file is reformatted. Tools like jest combined with child_process can automate this verification, giving you confidence that the hook behaves as expected.

Version Compatibility Tips

Git hooks can break when dependencies upgrade. Pin the versions of Husky, lint‑staged, Prettier, and ESLint in your package.json and schedule periodic reviews. When upgrading Node or switching package managers, verify that the hook scripts still resolve correctly.

Conclusion

When you Configure pre‑commit hooks to format and lint JS/TS, you automatically enforce consistent style and catch bugs early. This approach delivers big returns in code quality and team velocity. Start by adding the hook to a single branch, iterate on the configuration, and soon you’ll wonder how you ever committed without it. Take the first step today: run npm install --save-dev husky lint‑staged prettier eslint and watch your repository stay pristine.

Leave a Comment