
uv 0.12.0 landed on July 28 with one headline change that will quietly break developer workflows: uv init now creates a packaged src/ layout by default instead of dropping a flat main.py in the project root. That’s not the only breaking change — there are twelve in total — and at least one of them (SSL certificate enforcement) is the kind that silently passes code review and detonates in CI.
The Default Flip: src/ Layout Is Now Standard
If you run uv init after upgrading, your project structure looks different. Previously you got a flat main.py and a pyproject.toml with no build system. Now you get a src/<project-name>/ directory, a [build-system] table using uv’s own uv_build backend, and a [project.scripts] entry point.
Existing projects are completely unaffected. This only touches new project scaffolding. But any automation script, CI job, or internal template that calls uv init now produces a different directory structure — which means downstream scripts that expect main.py at the root will break silently.
The escape hatch is uv init --no-package, which restores the old flat layout.
Worth noting: this was actually the default in uv v0.3. It was dropped in v0.4 when hatchling was used as the build backend and confused newcomers. Astral’s own uv_build backend — stable since July 2025 — makes the default meaningful without the confusion. Simon Willison put it plainly after the release: “I’ve been avoiding the src layout in my own projects just out of inertia. I think it’s time I switched.”
The src layout is correct. It prevents the classic Python trap where import mypackage silently imports from your development directory instead of the installed version, which lets broken packages pass tests locally and fail in production. pytest recommends it. The cryptography library uses it. NASA projects use it. uv is finally making it the path of least resistance.
The Change That Will Break Your CI: SSL Certificate Enforcement
This one is subtle enough to survive code review and only surface in production. Before 0.12.0, if SSL_CERT_FILE or SSL_CERT_DIR pointed to a missing, empty, or invalid path, uv silently fell back to its default certificate roots and HTTPS requests worked fine. From 0.12.0 onwards, an invalid cert path means all HTTPS requests fail.
The real-world trigger: a CI runner where SSL_CERT_FILE was set to a certificate that was rotated months ago. Under the old behavior, it worked fine — uv ignored the bad path and used system certs. After upgrading to 0.12.0 on that same runner, every uv pip install fails with a certificate error that does not obviously point to the environment variable.
Before upgrading, audit your CI environment variables. If SSL_CERT_FILE is set, either fix the path or unset it entirely. This is the right security call — a cert override that silently fails defeats its own purpose — but the behavior change is sharp.
Archive Formats and Hash Strictness
Two more changes with real operational impact:
Archive formats: uv 0.12.0 enforces PEP 625, which means only .tar.gz source distributions are accepted. The previously tolerated .tar.bz2 and .tar.xz formats are rejected — including when referenced by an existing lockfile. If your uv.lock references packages in those formats, regenerate it with uv lock after upgrading.
Hash verification: If your requirements.txt uses --require-hashes, MD5-only hashes are now rejected. You need SHA-256 or stronger. Regenerate with uv pip compile --generate-hashes, which has always produced SHA-256 — but older tools that populated hashes may have used MD5.
Your Upgrade Checklist
Three things to verify before rolling out uv 0.12.0 to your team or CI infrastructure:
- Search for
uv initcalls in automation. Any script that invokesuv initand expects a flat layout needs either--no-packageadded or a directory structure update downstream. - Audit SSL environment variables. Run
env | grep -i certon your CI runners. IfSSL_CERT_FILEorSSL_CERT_DIRis set, verify the path resolves to a valid certificate file or unset it. - Regenerate lockfiles. Run
uv lockon each project after upgrading. This resolves any lingering references to old archive formats and updates hash algorithms where needed.
uv Is Still Accelerating
The 0.12.0 release dropped Monday; by Thursday, 0.12.1 is already out, adding per-package pre-release policies, local HTML flat indexes, and automatic fixes via uv check --fix. This is the pace of development under OpenAI-owned Astral: a breaking-change release followed three days later by the first patch.
The 126 million monthly downloads signal that the Python community has already decided on uv. The 0.12.0 defaults signal that Astral has decided what a well-structured Python project looks like. Both positions are defensible. The question for teams is whether they’re watching the release notes closely enough to catch the changes that land in between.













