# Check Placement by Hook Stage
## Rule
Checks MUST be placed in the appropriate hook stage based on execution time. Pre-commit is for fast checks (< 10s). Pre-push is for slow checks (< 60s). Tests go in pre-push, never pre-commit.
## Check Placement Guide
| Check | Hook Stage | Typical Time | Reason |
|-------|-----------|-------------|--------|
| ESLint / Ruff | pre-commit | 1-3s | Fast, staged files only |
| Prettier / Black | pre-commit | 1-2s | Fast formatting check |
| Gitleaks / secrets | pre-commit | 1-2s | Security, must not be skipped |
| Commitlint | commit-msg | < 1s | Message validation |
| Jest / Pytest | pre-push | 10-60s | Too slow for pre-commit |
| tsc --noEmit | pre-push | 5-30s | Needs full project |
| npm run build | pre-push | 10-60s | Full build verification |
| E2E tests | CI only | 2-10min | Too slow for any hook |
## Configuration
```yaml
# lefthook.yml
pre-commit:
parallel: true
commands:
lint:
glob: "*.{ts,tsx}"
run: npx eslint {staged_files}
format:
glob: "*.{ts,tsx,json,md}"
run: npx prettier --check {staged_files}
secrets:
run: gitleaks protect --staged --no-banner
commit-msg:
commands:
validate:
run: npx commitlint --edit {1}
pre-push:
parallel: true
commands:
test:
run: npm test -- --passWithNoTests
typecheck:
run: npx tsc --noEmit
build:
run: npm run build
```
## Anti-Patterns
- Running `npm test` in pre-commit (30+ second hooks get skipped)
- Running `tsc --noEmit` in pre-commit (needs full project context)
- Running E2E tests in any hook (too slow, use CI)
- Putting formatting checks in pre-push (should give immediate feedback)
- Not having any pre-push checks (tests never run before push)