As a developer, especially when managing code standards, your workflow matters.
You can write great code, but if you:
- forget to format it before committing,
- skip linting,
- or leave vague commit messages like
update
orfix bug
It all snowballs into a messy codebase that's hard to maintain and collaborate on.
Let me introduce you to three tools that can drastically improve your developer lifecycle:
✅ Husky
✅ lint-staged
✅ commitlint
These tools help enforce discipline and automation without slowing you down, and I've integrated them into my last project.
🔧 What is Husky?
Husky is a tool for managing Git hooks — scripts that run automatically during Git events like pre-commit
, commit-msg
, pre-push
, etc.
Think of it as your personal assistant that runs checks or commands every time you or your teammates interact with Git.
✅ Why Use Husky?
- Prevent bad code from being committed.
- Run tests, lint, or format files before commits.
- Block invalid commits before they reach your repo.
🎯 What is lint-staged?
lint-staged runs linters (or any command) on only the staged files (files that you’re about to commit), not your entire codebase.
✅ Why Use lint-staged?
- It's super fast.
- You don’t accidentally commit unformatted or buggy code.
- It keeps your commits clean and atomic.
📌 Example Use Cases:
- Run
Prettier
andESLint
only on changed files. - Validate Markdown or config files before committing.
📝 What is commitlint?
commitlint checks if your commit messages meet a defined convention, like Conventional Commits.
✅ Why Use commitlint?
- Keeps commit messages consistent and meaningful.
- Useful for changelogs, release automation, and team collaboration.
- Helps new developers follow the project's commit rules.
🚀 Real-World Setup in My Turborepo Project
I’ve used these tools in my own Turborepo-based MERN monorepo containing:
-
apps/frontend
(Next.js) -
apps/backend
(Express.js) apps/extension
packages/ui
Let’s walk through how to configure each tool with code examples:
📁 .lintstagedrc
Configuration
{
"apps/backend/**/*.{js,ts}": [
"prettier --write --config ./apps/backend/.prettierrc.mjs",
"eslint --max-warnings 0 --config ./apps/backend/eslint.config.mjs"
],
"apps/extension/**/*.{js,jsx,ts,tsx}": [
"prettier --write --config ./apps/extension/.prettierrc.mjs",
"eslint --max-warnings 0 --config ./apps/extension/eslint.config.js"
],
"apps/frontend/**/*.{js,jsx,ts,tsx}": [
"prettier --write --config ./apps/frontend/.prettierrc.mjs",
"eslint --max-warnings 0 --config ./apps/frontend/eslint.config.js"
],
"packages/ui/**/*.{js,jsx,ts,tsx}": [
"prettier --write --config ./apps/frontend/.prettierrc.mjs",
"eslint --max-warnings 0 --config ./apps/frontend/eslint.config.js"
],
"*.md": ["prettier --write"]
}
📁 .commitlintrc.json
Configuration
{
"extends": ["@commitlint/config-conventional"],
"rules": {
"type-enum": [
2,
"always",
[
"ci",
"chore",
"docs",
"feat",
"fix",
"perf",
"refactor",
"revert",
"style",
"assets",
"test"
]
]
}
}
✅ This enforces commit types like feat
, fix
, docs
, chore
, etc.
🔴 Invalid: updated code
✅ Valid: feat: add login screen
📁 Husky Git Hooks
You can install and enable Husky with:
pnpm dlx husky install
pnpm pkg set scripts.prepare="husky install"
git add . && git commit -m "chore: setup husky"
husky/pre-commit
npx lint-staged --allow-empty
→ Runs prettier and eslint only on staged files.
husky/commit-msg
npx --no-install commitlint --edit
npx --no-install commitlint --edit
husky/pre-push
npm run test && npm run build
→ Prevents pushing broken builds.
🧠 Summary: Why You Should Use These Tools
Husky
- What it Does: Hooks into Git to run scripts
- Why it Matters: Enforces quality and automation at each Git stage
Lint-staged
- What it Does: Lints only changed files
- Why it Matters: Keeps commits clean without slowing you down
Commitlint
- What it Does: Validates commit messages
- Why it Matters: Ensures consistent commit history for teams & tooling