Husky + Prettier + lint-staged Setup for Next.js
Set up Husky v9, Prettier, and lint-staged in your Next.js project. Step-by-step guide covering pre-commit hooks with the correct 2026 config.
On this page
Introduction
Most code quality issues are caught too late — in code review, or worse, in production. Husky, Prettier, and lint-staged give you an automatic check on every single commit, right on your machine, before the code ever leaves your editor.
This guide walks through the full setup for a Next.js project using the current versions of all three tools. If you've tried this before with a guide from 2022 and it didn't work, it's probably because Husky changed its configuration format in v9.
Step-by-Step Guide
What These Tools Do
Three tools, each with a distinct job. Together they form an automatic quality gate that runs on every commit:
Prettierformats your code automatically. You set the rules once — line length, single vs double quotes, trailing commas — and it handles the rest.lint-stagedruns linters only on the files you've staged for a commit, not your entire codebase. This keeps the pre-commit check fast even on large projects.Huskyconnects everything to Git. It installs scripts that run automatically at key moments — in this setup, immediately before a commit is finalized.
Install the Tools
From your Next.js project root, install the three dev dependencies. Next.js already ships with ESLint configured, so you don't need to install that separately.
npm install --save-dev prettier husky lint-stagedConfigure Prettier
Create a .prettierrc file in your project root. These are sensible defaults for a Next.js TypeScript project — adjust them to your team's preference:
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2
}Initialize Husky v9
This is where most guides go wrong. Husky v9 dropped the old .huskyrc file format. Run one command to initialize it:
npx husky initConfigure the Pre-Commit Hook
Open .husky/pre-commit — it was just created by husky init. Replace its contents with a single line that triggers lint-staged:
npx lint-stagedConfigure lint-staged
Add a lint-staged key to your package.json. This tells it which tools to run on which file types when they're staged:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,md}": [
"prettier --write"
]
}
}Test the Setup
Stage a file with a formatting issue and try to commit. lint-staged will run both tools automatically:
- If Prettier can fix the issue automatically, it will do so and the commit will succeed.
- If ESLint flags something it can't auto-fix (like an unused variable), it will print the error and block the commit.
- Try it both ways — this is the fastest way to understand exactly what the setup catches.
git add .
git commit -m "test commit"Common Issues and Fixes
These are the four most common problems developers hit after setting this up:
- Hooks not running after cloning. Someone ran
npm install --ignore-scripts, which skips thepreparescript. Fix: runnpm run preparemanually once. - `husky: command not found`. An old
.huskyrcorhusky.config.jsfrom a previous attempt is still present. Delete it and re-runnpx husky init. - `lint-staged` runs on all files, not just staged ones. The
.husky/pre-commitfile containsprettier --write .instead ofnpx lint-staged. Replace it withnpx lint-staged. - TypeScript errors not being caught. This is expected —
lint-stagedruns tools on individual files in isolation. TypeScript's type checker needs the full project to work. Addtsc --noEmitto apre-pushhook instead.
Frequently Asked Questions
- What changed between Husky v8 and v9?
- Husky v9 simplified the setup significantly. The
husky installcommand is gone, replaced byhusky init. The.huskyrcfile format is no longer supported. Hooks are now plain shell scripts in the.husky/directory, and thepreparelifecycle script handles automatic installation. - Why use lint-staged instead of running ESLint on the whole project?
- Running ESLint on a large codebase before every commit gets slow fast — 10, 20, 30 seconds per commit.
lint-stagedscopes the run to only the files you've changed, keeping pre-commit checks under a second on most projects. - Should I use Prettier, ESLint, or both?
- Both, for different reasons. ESLint catches code quality issues — unused variables, unreachable code, type errors when configured with TypeScript rules. Prettier handles formatting — indentation, line breaks, quote style. They don't overlap. Run ESLint first, then Prettier, so Prettier's final formatting pass is what gets committed.
- Will Husky hooks run in CI?
- By default, yes — but you usually don't want them to. In CI, you want to run the full lint and type-check directly, not via Husky. Set the
HUSKYenvironment variable to0in your CI config to skip Husky hooks:HUSKY=0 npm ci. - Does this setup work with Yarn or pnpm?
- Yes. Replace
npm install --save-devwithyarn add --devorpnpm add -D. The Husky init andlint-stagedconfiguration are identical — only the package manager command changes.
Husky v9, Prettier, and lint-staged take about five minutes to set up and save hours of back-and-forth over formatting in code review.
Keep the pre-commit hook fast — format and lint only staged files. Move tsc --noEmit to a pre-push hook where a slower check is acceptable.
Related Articles
How to Use Environment Variables in Next.js (Without Leaking Them to the Browser)
Learn how to use .env files in Next.js correctly. Understand NEXT_PUBLIC_, avoid common mistakes, and set variables in Vercel and Cloudflare.
TypeScript 7 (Project Corsa): What Next.js Devs Need to Know
TypeScript 7 rewrites the compiler in Go for 10x faster builds. Here's what it means for your Next.js project and what to do right now.