Skip to content
Latchkey

pre-commit stages: When Hooks Run

stages tells pre-commit which git phases a hook runs at, such as pre-commit, pre-push, or manual.

Not every hook should run on every commit. Slow or release-only checks can be scoped to pre-push or a manual stage you invoke explicitly in CI.

What it does

A hook stages list (or default_stages at the top level) restricts when the hook fires. The manual stage never runs automatically; it only runs when you call pre-commit run --hook-stage manual, which is handy for CI-only checks.

Common usage

.pre-commit-config.yaml
- repo: local
  hooks:
    - id: heavy-tests
      name: heavy tests
      entry: pytest -m slow
      language: system
      stages: [manual]
# in CI:
# pre-commit run --hook-stage manual --all-files

Stages

StageWhen it fires
pre-commit (commit)On git commit, against staged files
pre-pushOn git push
commit-msgAfter the commit message is written
manualOnly when invoked with --hook-stage manual
default_stagesTop-level default applied to hooks without stages

In CI

Use the manual stage for expensive checks you want only in the pipeline, then run pre-commit run --hook-stage manual --all-files as a dedicated step. Newer pre-commit renamed the commit stage to pre-commit; old configs using stages: [commit] still work but emit a deprecation note.

Common errors in CI

A hook that "does nothing" in CI is often scoped to stages: [manual] but invoked without --hook-stage manual. The deprecation message "[WARNING] hook id ... uses deprecated stage names (commit, push)" means you should rename them to pre-commit and pre-push. An unknown stage name raises InvalidConfigError.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →