Skip to content

How to set up prek hooks for a Python project

This guide assumes you have a Python project managed with uv. If you haven’t created a project yet, see the project creation tutorial.

prek is a Rust-based drop-in replacement for pre-commit that runs hooks faster, uses less disk space, and ships as a single binary with no Python dependency. It reads the same .pre-commit-config.yaml files, so the configuration in this guide also works with pre-commit. See the pre-commit version of this guide for the original tool.

Installing prek

Install prek as a CLI tool with uv:

$ uv tool install prek

Then install the Git hook in your project:

$ prek install

This places a hook script in .git/hooks/pre-commit that runs automatically on git commit.

Migrating from pre-commit

If the project already uses pre-commit, swap it out without changing any configuration:

$ pre-commit uninstall && prek install

The existing .pre-commit-config.yaml works as-is.

Creating the configuration file

prek reads the same .pre-commit-config.yaml format as pre-commit. Here is a starting configuration that uses Ruff for linting and formatting:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.11.12
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

The ruff hook runs the linter with auto-fix enabled. The ruff-format hook runs the formatter. They execute in order, so linting fixes are applied before formatting.

Tip

Run prek auto-update to update all hook versions to their latest releases.

Adding more hooks

Trailing whitespace and file endings

The pre-commit-hooks repository provides several lightweight checks:

repos:
  - 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

Using prek’s built-in hooks

prek ships with Rust-native implementations of common hooks that require no external toolchain. Use repo: builtin to access them:

repos:
  - repo: builtin
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml

Built-in hooks run faster than their Python equivalents because they skip virtual environment setup entirely.

Type checking with mypy

To run mypy as a hook:

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.16.0
    hooks:
      - id: mypy
        additional_dependencies: []

Add any type stub packages your project needs to additional_dependencies. For example, if your project uses requests:

        additional_dependencies: [types-requests]

A complete configuration

Combining built-in hooks with Ruff:

repos:
  - repo: builtin
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.11.12
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

Running hooks manually

To run all hooks against every file in the repository:

$ prek run --all-files

To run a specific hook:

$ prek run ruff --all-files

To list all configured hooks:

$ prek list

Skipping hooks temporarily

To bypass hooks for a single commit:

$ git commit --no-verify -m "WIP: work in progress"

Using prek in CI

Run hooks in CI to catch anything contributors skip locally. In a GitHub Actions workflow:

- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv tool install prek
- run: prek run --all-files

Troubleshooting

If hooks are not running on commit, verify the hook is installed:

$ prek install

To clear cached hook environments (useful after updating Python or hook versions):

$ prek clean
Last updated on

Please submit corrections and feedback...