Switch to hatchling
Move the build backend from uv_build to hatchling when a project outgrows it
The template builds with uv_build, which is the right backend for a pure
Python project: it is already part of uv, so there is no second tool in the
build path. Switch to hatchling when you need something uv_build does not
do — a compiled extension, or a build hook that generates files at build time.
Nothing else in the project depends on the backend. This is a reversible, four-line change.
Goal
Replace uv_build with hatchling as the build backend, leaving the package
layout and every other tool untouched.
Prerequisites
- A reason. If the project is still pure Python with no build-time codegen,
uv_buildis doing the job and this change buys nothing.
Steps
Swap the build-system table
In pyproject.toml, replace:
[build-system]
requires = ["uv_build>=0.12.5,<0.13.0"]
build-backend = "uv_build"
[tool.uv.build-backend]
module-name = "pythontemplate"with:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/pythontemplate"]Both tables say the same thing in different dialects: where the package lives.
uv_build infers it from the distribution name and needs module-name only
when the two differ; hatchling is told the path outright.
Relock
Nothing to do. Build backends are resolved by the build frontend at build
time, not locked as project dependencies — uv.lock records neither
uv_build nor hatchling, and relocking after this swap produces no diff.
If you change project dependencies while you are here, re-lock with
task uv:lock. Plain uv lock will not do it: mise.toml exports
UV_FROZEN=1, under which uv lock silently no-ops and still exits 0.
Verification
uv build
task dev:checkuv build should emit both a wheel and an sdist into dist/, and the gate
should stay green — no source file changes, so nothing else can move.
Notes
The wheel name does not change
Both backends normalise the distribution name the same way, so
python-template produces python_template-<version>-py3-none-any.whl either
way. Anything pinning the wheel name keeps working.
Adding an extension is a separate step
Switching the backend does not by itself let you ship compiled code. Hatchling
needs a build hook — hatch-build-scripts, or a custom hook — and the CI
matrix needs to build wheels per platform rather than the single
py3-none-any wheel the release workflow currently publishes.