{"post":{"slug":"how-to-set-up-pre-commit-hooks-2026","title":"How to set up pre-commit hooks in 2026","excerpt":"Pre-commit hooks catch formatting errors, lint failures, and secrets before they reach CI. Here is how to set them up reliably in 2026.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">P</span>re-commit hooks are the last line of defense before code leaves your machine. They catch the fast-and-cheap problems — formatting drift, obvious lint errors, accidental secret commits — so CI does not have to. In 2026, the tooling is mature and setup takes under ten minutes. Here is the canonical approach.\n\n## What changed in 2026\n\n- **Husky v10** dropped the `prepare` script pattern and uses `husky init` to write a native shell script, reducing setup to two commands.\n- **lint-staged 16** added parallel task execution — multiple formatters and linters run concurrently on staged file groups.\n- **`gitleaks` v9** ships a pre-built binary for all platforms and is the standard secrets scanner for git hooks.\n- **Node projects with pnpm** can use `pnpm dlx husky init` without a global install.\n\n## Install Husky and lint-staged\n\n```bash\nnpm install --save-dev husky lint-staged\nnpx husky init\n```\n\n`husky init` creates `.husky/pre-commit` and adds a `prepare` script. Replace the default content:\n\n```bash\n# .husky/pre-commit\nnpx lint-staged\n```\n\n## Configure lint-staged\n\nIn `package.json`:\n\n```json\n{\n  \"lint-staged\": {\n    \"*.{js,ts,jsx,tsx}\": [\n      \"eslint --fix --max-warnings=0\",\n      \"prettier --write\"\n    ],\n    \"*.{json,css,md,yaml}\": \"prettier --write\",\n    \"*.{js,ts}\": \"bash -c 'tsc --noEmit'\"\n  }\n}\n```\n\nAlternatively, create `lint-staged.config.mjs` for more complex logic.\n\n## Add a secrets scanner\n\nInstall `gitleaks` (pick the method for your OS):\n\n```bash\n# macOS\nbrew install gitleaks\n\n# Linux / CI\ncurl -sSfL https://raw.githubusercontent.com/gitleaks/gitleaks/main/scripts/install.sh | sh -s -- -b /usr/local/bin\n```\n\nAdd a second hook file:\n\n```bash\n# .husky/pre-commit (append)\ngitleaks protect --staged --redact\n```\n\n`gitleaks protect --staged` scans only staged diff content and exits non-zero if secrets are detected.\n\n## Hook execution order and types\n\n| Hook | When it runs | Typical use |\n| --- | --- | --- |\n| `pre-commit` | Before commit message entry | Lint, format, secrets scan |\n| `commit-msg` | After message written | Validate commit message format |\n| `pre-push` | Before `git push` | Type-check, heavier checks |\n| `post-checkout` | After branch switch | Install deps if lockfile changed |\n\nFor the `commit-msg` hook, enforce Conventional Commits:\n\n```bash\n# .husky/commit-msg\nnpx --no -- commitlint --edit \"$1\"\n```\n\n## Monorepo setup\n\nIn a monorepo with workspaces, Husky hooks live at the repo root. Configure lint-staged to scope commands to the right package:\n\n```json\n{\n  \"lint-staged\": {\n    \"packages/api/**/*.ts\": \"eslint --fix\",\n    \"packages/web/**/*.{ts,tsx}\": [\"eslint --fix\", \"prettier --write\"],\n    \"**/*.{json,md}\": \"prettier --write\"\n  }\n}\n```\n\n## How to pick what goes in a hook\n\n1. **Under 3 seconds total?** Fine for pre-commit.\n2. **Fails rarely and only on real problems?** Good — hooks that always pass are useless.\n3. **Requires a running server or DB?** Move it to CI.\n4. **Full type-check on a large project?** Put it in `pre-push`, not `pre-commit`.\n\n## Common mistakes\n\n**Hooks not executable.** Git hooks must have execute permission. Husky handles this, but if you manually create a hook file run `chmod +x .husky/pre-commit`.\n\n**Bypassing with `--no-verify`.** Some teams do this so often hooks become irrelevant. Keep hooks fast — under 3 seconds — so there is no incentive to skip.\n\n**Not committing the `.husky/` directory.** Husky hooks live in `.husky/` which must be committed. `.git/hooks/` is per-clone and never shared.\n\n**Running all files instead of staged.** Without lint-staged, `eslint .` on a large repo takes 30+ seconds. Always scope to staged files.\n\n## What to skip\n\n- **Full test suite in pre-commit.** Unit tests belong in CI where they can run in parallel with caching. In a pre-commit hook they add 30–120 seconds and will be skipped.\n- **Build step in pre-commit.** Build in CI; hook should only validate source.\n- **Custom shell scripts for formatting.** Use lint-staged instead of hand-rolled `for` loops over staged files.\n\n## FAQ\n\n**How do I skip the hook for one commit?**\n`git commit --no-verify -m \"wip\"`. Use sparingly; CI will still catch problems.\n\n**Does Husky work with pnpm and Yarn Berry?**\nYes. Replace `npx` with `pnpm dlx` or `yarn dlx` in hook files, and run `pnpm dlx husky init` during setup.\n\n**Can I share hooks across a team?**\nYes — commit `.husky/` to the repository. Every developer gets the hooks after `npm install` runs the `prepare` script.\n\n**What if a developer does not have a tool installed?**\nGuard with a check: `command -v gitleaks &>/dev/null && gitleaks protect --staged`. The hook skips gracefully if the binary is missing; document the install step in the README.\n\n## Where to go next\n\n- [How to set up Prettier in 2026](/blog/how-to-set-up-prettier-2026)\n- [How to write a GitHub Action in 2026](/blog/how-to-write-a-github-action-2026)\n- [How to write a README in 2026](/blog/how-to-write-a-readme-2026)","hue":307,"metaTitle":"How to Set Up Pre-Commit Hooks in 2026","metaDescription":"Complete guide to pre-commit hooks in 2026 using Husky and lint-staged. Covers install, config, secrets scanning, and keeping hooks fast.","keywords":["how to set up pre-commit hooks 2026","husky pre-commit hook 2026","lint-staged setup 2026","git hooks javascript 2026","pre-commit hook secrets scanning","gitleaks pre-commit","pre-commit hook best practices","husky lint-staged monorepo","git pre-commit automation","code quality automation 2026"],"tldr":["**Hooks run on staged files only** — lint-staged makes them fast even in large monorepos.","**Husky v10 uses a native shell script** — no Node.js startup cost, hooks run in ~200 ms.","**Secrets scanning belongs in a pre-commit hook** — `gitleaks` or `detect-secrets` catches credentials before they are committed.","**Keep hooks fast** — anything over 5 seconds trains developers to skip with `--no-verify`.","**Skip:** running the full test suite in a pre-commit hook — that is what CI is for; hooks should only block on things that take under 3 seconds."],"readTime":"3 min read","wordCount":756},"related":[{"slug":"what-is-a-git-hook-2026","title":"What Is a Git Hook in 2026? Automate Your Workflow","excerpt":"A git hook is a script that git runs automatically at a specific point, like before a commit or before a push. Here is what git hooks are, what they are good for, and how to set one up in 2026.","category":"code","date":"July 17, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":320},{"slug":"how-to-set-up-prettier-2026","title":"How to set up Prettier in 2026","excerpt":"Prettier ends code-style debates by enforcing a single format on save. This guide covers installation, config, editor integration, and CI enforcement in 2026.","category":"code","date":"March 16, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":306},{"slug":"how-to-write-clean-functions-2026","title":"How to write clean functions in 2026","excerpt":"Clean functions are the single highest-leverage thing you can do for code quality. Here is the 2026 playbook with concrete rules and real examples.","category":"code","date":"March 18, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":318}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-set-up-parental-controls-2026","title":"How to set up parental controls in 2026: screen time, filters, and location","excerpt":"Built-in parental controls on iOS, Android, Windows, and routers are more capable than ever in 2026. Here is how to configure them without a paid app.","category":"tech","date":"April 3, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":236},"older":{"slug":"how-to-set-up-ssl-2026","title":"How to set up SSL in 2026: TLS, certificates, and HTTPS done right","excerpt":"HTTPS is non-negotiable in 2026 — browsers flag plain HTTP, and search engines penalize it. Here is how to get certificates, configure TLS, and stay secure.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":309}}