thiagowfx's avatar

Β¬ just serendipity πŸ€ (not just serendipity)

migrating from pre-commit to prek

β€’ 256 words β€’ 2 min

Previously.

Today I learned: prek is a drop-in replacement for pre-commit, rewritten in Rust. Same .pre-commit-config.yaml, same hook ecosystem, much faster.

A single binary with zero dependencies, much faster than the original pre-commit, drop-in compatible.

Install:

shell
% brew install prek
# or
% cargo install prek

Then swap the command. Nothing else changes:

diff
-pre-commit run --all-files
+prek run --all-files

Or skip the swap entirely: prek install -f drops in a shim that replaces the pre-commit binary, so existing scripts and git hooks keep working unchanged.

The CI workflow on this blog (prek.yml) now uses j178/prek-action instead of pre-commit/action, and the monthly autoupdate job (prek-autoupdate.yml) runs prek auto-update --freeze β€” the --freeze flag works the same.

The benchmark is what sold me. On cold caches, prek is around 10x faster at resolving and installing hooks; on warm runs, the difference is smaller but still noticeable.

Two other niceties pre-commit does not have:

  • Split configs across multiple files. prek supports multi-file configs, so hooks can live next to the subproject they belong to in a monorepo instead of piling up in a single top-level YAML.

  • Run against a commit or a range. prek run --from-ref A --to-ref B restricts the run to files changed between two refs β€” much faster than prek run -a because only the touched files are inspected. Example: lint everything on the current branch since it diverged from master:

    shell
    % prek run --from-ref "$(git merge-base master HEAD)" --to-ref HEAD

The .pre-commit-config.yaml file stays put, and pre-commit.ci still reads it. No lock-in.