Repository navigation
Replace pre-commit with prek for faster linting #143148
Copy link
Copy link
Closed
Labels
infraCI, GitHub Actions, buildbots, Dependabot, etc.CI, GitHub Actions, buildbots, Dependabot, etc.type-featureA feature request or enhancementA feature request or enhancement
Description
Feature or enhancement
Proposal:
First, I hope this is the correct issue template. If not, please let me know, and I can resubmit the proposal using the proper template.
prek is a "reimagined version of pre-commit, [...] designed to be a faster, dependency-free and drop-in alternative".
It has already been adopted by major projects from Apache, FastAPI, and Django (see prek/Who is using prek?).
Running prek against the entire CPython codebase yields a speedup of almost 2.5x without a cache and 1.25x with a warm cache.
hyperfine --warmup 2 --runs 5 \
--prepare "prek cache clean" "prek run --all-files" \
--prepare "pre-commit clean" "pre-commit run --all-files"
Benchmark 1: prek run --all-files
Time (mean ± σ): 19.835 s ± 0.290 s [User: 50.857 s, System: 6.248 s]
Range (min … max): 19.527 s … 20.201 s 5 runs
Benchmark 2: pre-commit run --all-files
Time (mean ± σ): 48.944 s ± 0.448 s [User: 76.063 s, System: 6.096 s]
Range (min … max): 48.522 s … 49.681 s 5 runs
Summary
prek run --all-files ran
2.47 ± 0.04 times faster than pre-commit run --all-fileshyperfine --warmup 2 --runs 5 \
"prek run --all-files" \
"pre-commit run --all-files"
Benchmark 1: prek run --all-files
Time (mean ± σ): 6.763 s ± 0.124 s [User: 35.990 s, System: 2.134 s]
Range (min … max): 6.589 s … 6.900 s 5 runs
Benchmark 2: pre-commit run --all-files
Time (mean ± σ): 8.537 s ± 0.048 s [User: 43.797 s, System: 1.903 s]
Range (min … max): 8.484 s … 8.608 s 5 runs
Summary
prek run --all-files ran
1.26 ± 0.02 times faster than pre-commit run --all-filesHas this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
No response
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
infraCI, GitHub Actions, buildbots, Dependabot, etc.CI, GitHub Actions, buildbots, Dependabot, etc.type-featureA feature request or enhancementA feature request or enhancement
Activity
StanFromIreland commentedon Dec 24, 2025
CC @hugovk
AA-Turner commentedon Dec 24, 2025
I don't think we should yet wholesale replace, prek is still on 0.x, and explicitly notes in the README that it is not at parity etc.
However, using prek if pre-installed feels reasonable, we already do this with uv.
A
juhannc commentedon Dec 25, 2025
What's blocking parity with pre-commit is the lack of the
gccommand to clean only unused objects vs. cleaning the entire cache and some missing languages for hooks that pre-commit supports (cf. prek/TODO). Given preks speed in installing new hooks, I feel like the missinggccommand is not critical. And regarding the missing language support, none of those are required for the hooks in CPython. But I understand if you are hesitant to switch to prek. In that case, we can leave the issue and PR open until prek evolves further.picnixz commentedon Dec 25, 2025
Personally, I don't want to switch to yet another tool. I'm not against changing the CI itself but I'm against changing something that works with my local configuration (that is, I'm ok with the Makefile picking either prek or pre-commit, but I don't want to be forced to install it).
Usually, we prefer closing issues & PRs instead of keeping them open as we never know when it will be "ready" (it's not a problem to reopen the issue and PR afterwards).
juhannc commentedon Dec 25, 2025
I totally understand your hesitation to change a running system. What about making prek the new default for new developers (as per the devguide), but changing the Makefile to fallback to pre-commit? As of right now, this would surely be possible, although I see prek developing features pre-commit never implemented (and probably never will), such as priority, which allows for a custom order of execution and running hooks in parallel, potentially increasing the speed gain even further. This is obviously stuff for a separate issue, but would require everyone to switch to prek. But yes, in the meantime, a two-pronged approach would work and would be transparent to the developer. Both tools would work just fine.
AA-Turner commentedon Dec 25, 2025
Looking at the numbers again. ~8.5s to ~6.5s isn't massively compelling for the extra complexity here.
In terms of CI, linting is already one of the fastest jobs, and hence not on the critical path.
I think for now we should hold off on making this change. I'll close in a few days unless there's opinions to the contrary from other core devs.
A
hugovk commentedon Dec 26, 2025
I support this.
I've been using prek for months (https://hugovk.dev/blog/2025/ready-prek-go/) and have switched most of my projects over. I'm using it locally with Git for CPython (not via
make check) and all the otherpython/repos too.Ruff and uv are also still on 0.x :) I think all the hooks I need across all my projects are supported by prek. Everything we use here is already supported.
Fair enough, although the Makefile uses a venv and does everything for you -- when you run
make check, if pre-commit isn't in the venv, it installs and uses it from the venv. So if we used prek in the venv, it would take care of that for you too, and you wouldn't notice, except for much faster runs.Two seconds is a good improvement for pre-commit, when run locally, this is a worthwhile improvement. And ~20s vs ~49s is huge for uncached! (With extra config, prek also allows running hooks in parallel, which would be even quicker.)
👍
I suggest:
picnixz commentedon Dec 29, 2025
I also want to mention that some core devs were already skeptical about pre-commit (IIRC, @encukou) as it would install something that one does not necessarily want (even if isolated in a venv). Likewise, django (framework, not the website project) rejected the change.
juhannc commentedon Dec 29, 2025
Exactly, although I guess that should be a different pull request.
So, just to get it straight, you propose to first look for a system prek. If that doesn't exist, look for pre-commit from the venv. And what if that also doesn't exist? Should pre-commit be installed or prek?
I would propose the following to ease the way for a future with full prek adoption, especially with new developers coming in:
Where prek will be installed in the venv if all checks fail.
That way, developers who are already accustomed to pre-commit will stay with pre-commit (and have an easy way to do so by installing pre-commit system-wide). But new developers will start with prek and won't have to switch in the future
hugovk commentedon Dec 29, 2025
That was a different change: django/django#20449 replaces Flake8+isort+Black in the CI with prek. They don't already run pre-commit in CI, so it's not a drop-in replacement.
Indeed, the Django website did accept the simpler pre-commit -> prek replacement in django/djangoproject.com#2252, which is similar to this PR.
4 remaining items
dolfinus commentedon Dec 30, 2025
IMHO the more important feature prek 0.2.23+ has is priority - hooks that modify file content (ruff format, etc) can be run sequentially, and read-only hooks (ruff check, mypy, github workflow linters) can be run in parallel. For large number of read-only hooks the speed up can be huge.
Hook installation speed with cold cache is a nice improvement, but this is important only in CI workflows, not on local machine.
picnixz commentedon Dec 30, 2025
And I don't want tools that are not widely used as others. I'm ok with ruff, etc because those are tools I can trust and others can trust. It's more about how widespread
prekis. If it were used as much aspre-commitI'd probably have no issue with it, but for now, I definitely want to see whether the project will be as wide spread aspre-commit. To be clear, I'm willing to cast my core dev vote against the change if I'm forced to installprek. What I eventually want is one tool, not multiple ones used multiple projects that then pollute my global~/.cachefolder. FTR, I'm usinguvx pre-commitbecause I have too many Python versions installed and my default Python version (thanks to my OS) is Python 3.6 (though I may need to update it at some point, I was waiting for OpenSUSE Leap 16.0 to come out) and I prefer having very small system-wide installations.In this case, I would install nothing and leave it to the developer. It's their choice to install additional software and their choice whether they want to trust it.
There is a huge warning about it:
In this case, using priority but ending up with warnings is definitely something I don't want either.
emmatyping commentedon Dec 30, 2025
Regarding priority, I have doubts as to the correctness of running hooks in parallel, that seems likely to have unexpected failure modes.
I also agree with all of the points @picnixz made, especially that I don't think prek is widely used enough to adopt in CPython yet.
gh-143148: Replace pre-commit with prek in CI (#143149)
pythongh-143148: Replace pre-commit with prek in CI (pythonGH-143149)
pythongh-143148: Replace pre-commit with prek in CI (pythonGH-143149)
[3.13] gh-143148: Replace pre-commit with prek in CI (GH-143149) (#14…
[3.14] gh-143148: Replace pre-commit with prek in CI (GH-143149) (#14…
hugovk commentedon Jan 8, 2026
OK, CI is updated to use prek, we can revisit later about using it in the
Makefilewhen adoption is higher. Right now, pre-commit has 81m/month downloads, and prek is 14m/month.If you're not using the
Makefile, you can already use prek instead of pre-commit if you prefer.I think the trick is to keep the existing order for hooks that can write (that is, don't define a priority, and they'll be run in sequential order), but the read-only hooks can then run in parallel afterwards (so give them all something like
priority: 100).I'm running with this in a
.prek.yaml(via an alias) and haven't seen any problems (yet). It's also 0.8 seconds faster, 2.6s compared to 3.4s without (and 2.1s faster than pre-commit's 4.7s).Anyway, we can also reconsider adding
priorityin the future when switching to prek in theMakefile.pythongh-143148: Replace pre-commit with prek in CI (python#143149)
vivodi commentedon Mar 23, 2026
I recommend migrating directly to the pre-commit.ci GitHub app instead of the approach in this issue.
Running prek within GitHub Actions lacks persistent caching, forcing CI to re-download and reinstall all hooks from scratch on every run. In contrast, the pre-commit.ci GitHub app caches environments efficiently, ensuring time is spent only on executing hooks rather than setup. This would be significantly faster than both existing options.
I opened the issue #146317 Replace prek GitHub Action with pre-commit.ci GitHub app for better performance for this.
j178 commentedon Mar 23, 2026
@vivodi Did you check that? Where’s that claim coming from?
I just looked at the logs from the latest
lintjob:https://github.com/python/cpython/actions/runs/23422492043/job/68130457779
From what I can see,
prek-actiondid reuse the cached hooks and didn’t reinstall them.vivodi commentedon Mar 23, 2026
I just tested it—running via the pre-commit.ci GitHub app takes about 38 seconds, which is roughly the same as running
prekin GitHub Actions.Sorry for the confusion earlier, and apologies for the noise.