
Yesterday Michał Górny, a Gentoo developer who works on its Python packaging, published a plea not to use uv-build. It opens with the event that prompted it: "yet another dozen packages lose keywords on Gentoo because of a single key dependency switching to uv-build." He is careful to say he has no quarrel with uv or with Astral, whose tools he calls "good tools with a nice and responsive upstream." His complaint is about one line in a configuration file, and about who pays for it.
I think he is right on the narrow point, and the narrow point is worth five minutes of anyone's morning who publishes a Python package.
What a build backend is, briefly
A Python project's pyproject.toml has a [build-system] table. It names a build backend, the program that turns a directory of source into an installable wheel. PEP 517 made this pluggable: any front end (pip, uv, build) can drive any backend.
uv-build is Astral's backend. Its documentation describes it as "a great choice for most Python projects" and lists the benefits: sensible defaults with little configuration, tight integration with uv, validation of project metadata, and speed. The same page states that it "currently only supports pure Python code." Running uv init --lib writes it into a new library's pyproject.toml for you.
So the backend exists to package pure Python, and it is itself compiled Rust.
The numbers, checked
Górny gives three figures. I checked each against PyPI today.
- Size. He says the 0.13.0 wheels run from 1.2 to 1.5 MiB. PyPI lists eighteen platform wheels for that release, from 1,236,734 bytes (macOS on Apple silicon) to 1,566,858 bytes (Linux on ppc64le). That matches.
- The comparison. He says the flit-core wheel is 45 KiB. The current release, 4.1.0, is 45,622 bytes, one file for every platform, with no dependencies declared. By my division the uv-build wheel is between 27 and 34 times the size.
- Release rate. He says twelve releases in the thirty days before he wrote. PyPI shows twelve, from 0.12.14 on 15 September to 0.13.0 on 9 October.
The third alternative he names, hatchling, has a 78,748-byte wheel and declares five dependencies of its own on current Python.
The one figure I cannot check is his estimate that the speed advantage is "in the ballpark of 100 ms". Astral's page calls the backend "very fast" and gives no measurement, so that number is Górny's and should be read as an estimate from someone arguing a case.
Who actually runs the backend
Most people who install a pure-Python package never run its backend at all. They download a wheel that was built once, on the author's machine or in CI, and unpack it. Górny says so himself.
The backend runs for the author, for contributors, for CI, and for anyone who builds from the source distribution. That last group includes distributions that build everything from source as a matter of policy. For them, a package that names uv_build in its build requirements now requires a Rust toolchain and a compile before a single Python file is copied. On Gentoo the compile is of uv itself: its uv-build package is a thin wrapper that depends on the full uv executable, to avoid building two largely overlapping binaries.
Gentoo's uv ebuild shows what that costs. It asks for 3 GB of free disk before it starts. It rewrites the link-time optimisation setting from fat to thin, with a comment saying this "makes it possible to actually build uv on 32-bit PPC". On 32-bit Arm it turns optimisation off entirely, with the comment "otherwise, rustc/llvm runs out of address space". And three days ago Górny filed a bug against rustix, a library uv depends on, because symbols it needs are missing on SPARC64. That issue is open.
This is where the keywords come in. A keyword is Gentoo's per-architecture mark that a package is known to work there. The current uv-build ebuild carries nine: amd64, arm, arm64, loong, ppc, ppc64, riscv, s390 and x86. Gentoo's page for the package shows alpha, hppa, mips and sparc as unknown. A package cannot be marked as working on an architecture where its build tool does not build. When a widely used library switches backend, every package above it on those architectures loses its mark too. That is the dozen in his opening sentence.
The flat-pack problem
Think of flat-pack furniture shipped with screws that need an unusual driver bit. The manufacturer owns the bit, so its own assembly line is a fraction quicker. Every customer has to get hold of the bit before the first screw goes in. Most can order one. A few live where it has to be made by hand, and they are the ones writing in.
The manufacturer never sees that cost, because it does not arrive as a bug in the furniture. Here it arrives as a line removed from a distribution's package list, in a repository the author has probably never opened.
What makes this an operations question is the default. A build backend chosen deliberately is a trade-off the author has made. A build backend written into the file by uv init is a dependency nobody on the project decided to take, imposed on everyone downstream who builds from source.
What to do with this
It takes about a minute to find out where you stand.
- Read your own
[build-system]table. If it namesuv_buildand you did not put it there, a project template did. - Ask what you are using it for. If the answer is the metadata validation or the zero-configuration layout, those are real benefits and the docs describe them accurately. If the answer is consistency with uv, PEP 517 already gives you that with any backend.
- If you switch, verify the output. Flit's documentation gives the replacement as
requires = ["flit_core >=3.11,<5"]andbuild-backend = "flit_core.buildapi". Backends differ in how they find your module and which files they include, so build a wheel before and after and compare the file lists (python -m zipfile -lon each wheel will print them). The package should be identical. - Count your build requirements as dependencies. They rarely appear in a lock file or a dependency review, and they are code that must run on someone else's machine before yours can.
Who this is for
It is for authors of pure-Python libraries, particularly ones that other packages depend on, and for anyone who keeps a project template that a team copies.
It is not for application developers who never publish a source distribution. If your code ships as a container image or a deployed service, your backend choice reaches nobody, and uv-build's defaults are a reasonable convenience. It is also only one side: Astral has not, as far as I can find, answered the post, and a backend that validates metadata before upload may prevent failures that a distribution packager would otherwise find later.
What I take from it is a question about defaults in scaffolding tools generally. The command that creates a project decides more than its layout. Which of the lines in your own project file were written by a generator, and who downstream is running them?