pre-commit Hooks
pre-commit runs linting, formatting, and type checks automatically before each git commit. Problems get caught locally in seconds instead of in CI minutes later.
Search across all documentation pages
pre-commit runs linting, formatting, and type checks automatically before each git commit. Problems get caught locally in seconds instead of in CI minutes later.
uv add --group dev pre-commit
uv run pre-commit install# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-formatuv run pre-commit run --all-filesWhen to reach for this:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.14.0
hooks:
- id: mypy
additional_dependencies: [pydantic>=2]
args: [src/]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: [--maxkb=500]uv run pre-commit install
git commit -m "feat: add billing module"
# ruff + mypy run automatically; commit blocked on failureWhat this demonstrates:
--fix auto-corrects before blockingpre-commit install writes a .git/hooks/pre-commit scriptgit commit, each hook runs in an isolated environmentpre-commit run --all-files simulates a full run (useful in CI)| Hook | Typical time | Scope |
|---|---|---|
| ruff | <1s | Staged files |
| ruff-format | <1s | Staged files |
| mypy | 5-30s | Configured paths |
| trailing-whitespace | <1s | Staged files |
rev - stale rule sets. Fix: pre-commit autoupdate quarterly.pre-commit install in README; add CI pre-commit run --all-files.--exit-non-zero-on-fix re-stages issue. Fix: use the arg; re-add fixed files.rev in config; CI runs same config.| Alternative | Use When | Don't Use When |
|---|---|---|
| CI only | Very small team | Developers push broken code often |
| lefthook | Need faster parallel hooks | Ecosystem is smaller |
| husky | Monorepo with JS + Python | Python-only repo |
git commit --no-verify (use sparingly, never in team policy by default).
pre-commit run --all-files or pre-commit run ruff --all-files.
For small projects yes. For large codebases, CI-only mypy is faster for dev flow.
Add a repo entry to .pre-commit-config.yaml and run pre-commit install.
Yes. pre-commit supports Windows with Python installed.
Commit .pre-commit-config.yaml. Every dev runs pre-commit install.
Yes: pre-commit run --all-files as a CI step. Catches devs who skip install.
exclude: ^migrations/ in the hook config or types filter.
Use additional_dependencies in the hook config (as with mypy + pydantic).
Quarterly or when upgrading ruff/mypy versions in pyproject.toml.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026