uv 0.12.0, released July 28, 2026, changes the default project created by uv init and tightens several validation and safety checks. Most users should be able to upgrade without changes, according to Astral’s 0.12.0 changelog, but packaging templates, prerelease resolution, script discovery, and legacy distributions deserve a check. Existing projects are not converted to the new layout.
What changed in uv 0.12?
The most visible change is that a new application initialized with uv init is now a package by default. The release also changes how uv validates artifacts and hashes, chooses prereleases, discovers projects for scripts, and handles certain paths and virtual environments. These are changes in uv 0.12.0 behavior; check uv --version when diagnosing an issue because later 0.12.x releases may include additional fixes.
As an Amazon Associate I earn from qualifying purchases.
Why does uv init create a src/ project now?
In uv 0.12, the default application layout declares the uv_build build backend, puts source code in src/<project_name>/, and adds a [project.scripts] entry. That makes the project installable in its environment, importable, and invokable as a command. Existing projects are unaffected; this change applies to newly initialized projects.
Recommended Free Tools
For example:
uv init example
cd example
uv run example
To initialize without packaging, use uv init --no-package example or uv init --bare. Use --build-backend if you want to request a different backend. See the project initialization documentation for the current options.
#1 Best Overall
Check build-backend bounds in templates
The release notes say uv 0.12 does not introduce breaking changes to uv’s build-backend configuration. A restrictive version ceiling can still prevent the backend from resolving: for example, uv_build>=0.11.32,<0.12 excludes 0.12. A bound such as uv_build>=0.11.32,<0.13 admits it. Review the actual requirement in project templates rather than copying a generated version range blindly; generated requirements can change across uv releases.
Which artifact and security checks are stricter?
Source distributions and archive compression
uv 0.12 rejects legacy source distributions ending in .tar.bz2 or .tar.xz, including when an existing lockfile references them. Legacy ZIP source distributions remain supported. Rebuild affected distributions as .tar.gz and regenerate lockfiles that reference the rejected archives.
For ZIP-based wheels and archives, supported compression methods are stored, DEFLATE, and zstd. bzip2, LZMA, and XZ compression are rejected.
Rank #2
Wheels that could replace the interpreter
uv now rejects wheels containing files that could overwrite the environment’s Python interpreter. This includes case-insensitive names such as Python, python.py, and Python.exe, as well as files installed through wheel data paths that could replace the interpreter. The changelog specifies no opt-out: rename the conflicting files and rebuild the wheel.
Hash-checking requirements
A --require-hashes directive in requirements.txt now enables hash-checking mode for uv pip install and uv pip sync; it is no longer merely warned about and ignored. Every requirement must be pinned and hashed. MD5-only hashes are rejected, so provide a secure digest such as SHA-256. If hash checking was not intended, remove the directive instead of leaving an incomplete file.
How did dependency resolution and project discovery change?
Prereleases are considered when needed
The default prerelease policy is now if-necessary: uv tries stable candidates first and can fall back to prereleases when constraints require them, including constraints introduced transitively. When stable and prerelease versions are both possible, resolution may choose a different version than earlier uv behavior.
The old if-necessary-or-explicit policy name remains as a deprecated alias. Other documented policies include disallow, allow, and explicit; set one with --prerelease when a project requires a specific policy.
Scripts now guide project discovery
When you run uv run path/to/script.py, uv starts project and workspace discovery from the script’s directory. A script in another project can therefore use a different environment than the one implied by your current working directory. Select the project explicitly when needed:
uv run --project . other-project/script.py
The selected path must identify a valid project. Missing or invalid --project paths now fail early. uv init --project is rejected because --project selects an existing project: give uv init a positional path to initialize, or use --directory to change the working directory.
Relative package-index paths follow --directory
When you provide relative package-index or find-links paths on the command line alongside --directory, those paths are now resolved relative to the selected directory. Absolute paths and indexes from configuration files are unaffected. uv add also preserves absolute local dependency paths; use relative paths when portability matters, since absolute paths tie a project to a particular filesystem location.
What should you check before upgrading or running a command?
- Project templates: check whether a
uv_buildupper bound excludes version 0.12. - Private or legacy packages: inspect source-distribution formats and ZIP compression used by wheels and archives.
- Requirements files: find
--require-hashesand confirm every requirement is pinned with a secure hash. - Scripts outside the current project: decide whether script-relative discovery is intended; use
--projectto select a project deliberately. - Commands using
--directory: verify the base directory for relative index andfind-linkspaths. - Cleanup scripts: verify the target before using
uv venv --clear.
How to choose and inspect the Python interpreter
uv can download a compatible Python interpreter automatically. The selected interpreter depends on the project’s requires-python, an explicit --python request, pins, and uv’s discovery order; a discovered system interpreter may be the first compatible one rather than the newest. Available managed Python downloads are bundled per uv release, so the list can vary by version. The Python versions documentation describes request formats and discovery behavior.
Free tools Windows power users keep installed
One-click scans. No signup required.
Pin a project’s Python request
Use uv python pin to write a .python-version file:
uv python pin 3.12
A version-number request is recommended for interoperability with other tools. uv looks for .python-version in the working directory and its parents, subject to project and workspace boundaries. The pin is a request that participates in interpreter selection; it does not by itself describe every project compatibility constraint.
Best Value
Install or inspect Python
uv python install 3.12
uv python find
uv python find --system
uv python install 3.12 can download a compatible interpreter. By default, uv python find may select a Python in a discovered .venv; --system ignores virtual environments. uv accepts requests such as major/minor/patch versions, version specifiers, variants, and implementation requests.
To control automatic downloads, consult the current Python version configuration guidance and select the intended interpreter explicitly. Do not assume that a system search returns the newest installed Python: uv’s system search can return the first compatible interpreter it finds.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Quick command cheatsheet
| Task | Command | Key behavior |
|---|---|---|
| Start a packaged application | uv init example |
Creates a packaged project by default in uv 0.12. |
| Start without packaging | uv init --no-package example or uv init --bare |
Uses an unpackaged initialization. |
| Run a script | uv run script.py |
Project discovery starts from the script’s directory. |
| Select a project | uv run --project path ... |
The selected path must be a valid project. |
| Pin Python | uv python pin 3.12 |
Writes a .python-version request. |
| Install Python | uv python install 3.12 |
Can download a compatible interpreter. |
| Inspect Python selection | uv python find or uv python find --system |
--system ignores virtual environments. |
| Clear a virtual environment | uv venv --clear |
Refuses to clear a target that is not a virtual environment unless forced. |
In a project, uv run updates the environment before invoking a command. The project guide says a normal project’s first project command—such as uv run, uv sync, or uv lock—creates .venv and uv.lock when needed. See the project guide.
Other 0.12 compatibility changes worth knowing
- Broken
.venvsymlinks and virtual-environment metadata errors are reported rather than skipped during discovery. This prevents uv from silently finding and modifying an unrelated ancestor environment. uv python install <minor> --reinstallnow reinstalls matching installed patch versions instead of implicitly upgrading to the latest patch. Use--upgradefor upgrade behavior; combine--upgrade --reinstallto reinstall only the latest patch.uv lock --upgrade-groupnow requires the named dependency group to exist.- PyPy releases available only in unsupported bzip2 archives can no longer be installed with
uv python install; newer releases with supported archives remain available. uv publishskips distributions with non-normalized filenames instead of warning and attempting an upload.
These are selected behavior changes from the 0.12.0 release notes, not an exhaustive list of every 0.12.x fix. Check the uv changelog and your installed version when investigating a patch-specific problem.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




