# uv 0.12 Makes Every New Project a Package


Run `uv init` on 0.12 and the `main.py` you expected is not there.

```console
$ uv init example
$ cd example
$ uv run example
Hello from example!
```

Source code now lives in `src/example/__init__.py`, `pyproject.toml` carries a `[build-system]` using `uv_build`, and a `[project.scripts]` entry turns `example` into a runnable command. That is the headline breaking change in [uv](https://pydevtools.com/handbook/reference/uv.md) 0.12.0, released July 28, 2026.

## uv shipped this default once before

Packaged-by-default is how `uv init` behaved back in v0.3. uv dropped it in v0.4 because the generated `[build-system]` pointed at Hatchling, and newcomers found an unexplained third-party [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md) confusing. uv now ships its own backend, `uv_build`, so the layout returns without a second tool to explain.

## The project installs itself now

The flat layout could declare dependencies but was never installed into its own virtual environment. A packaged project is, in editable mode, on the first `uv run`. Tests can `import example` without path manipulation, and other projects can depend on it directly.

Watch for one side effect: every `uv add` rebuilds and reinstalls your project alongside the new dependency, so the output gains a line like `~ example==0.1.0 (from file:///path/to/example)`.

## Existing projects keep working

Only new `uv init` runs change. The one thing to check before upgrading is an upper bound on `uv_build` in your `[build-system]` table. Widen it so the backend can move to 0.12:

```toml
[build-system]
requires = ["uv_build>=0.11.32,<0.13"]
build-backend = "uv_build"
```

## Get the flat layout back with --no-package

```bash
uv init --no-package example
```

That still produces the `main.py` project with no build system, which remains the right shape for a script or an internal tool you never distribute. [uv init: project types, flags, and examples](https://pydevtools.com/handbook/explanation/understanding-uv-init-project-types.md) compares every layout side by side.

`--package` also still works and now matches the default, so older tutorials that pass it produce the same project they always did.

## Scan the rest of 0.12.0 before upgrading

Four other breaking changes ship in the same release:

- **Source distributions must be `.tar.gz`.** [PEP 625](https://peps.python.org/pep-0625/), the standard that fixed sdist filename and format ambiguity, requires it. `.tar.bz2` and `.tar.xz` are now rejected, including when referenced by an existing lockfile. Legacy `.zip` sdists still work.
- **Pre-release handling defaults to `if-necessary`.** uv tries stable candidates first and falls back to pre-releases only when nothing stable satisfies the constraints. This matches pip and finally resolves pre-release requirements discovered in a dependency's metadata.
- **`--require-hashes` inside a `requirements.txt` is enforced.** uv previously warned and installed anyway. MD5-only hashes are rejected in hash-checking mode.
- **Wheels cannot overwrite the interpreter.** uv now rejects case variants like `Python.exe` and data files that would install over the virtual environment's Python.

## Learn more

- [uv init: project types, flags, and examples](https://pydevtools.com/handbook/explanation/understanding-uv-init-project-types.md)
- [How to upgrade uv](https://pydevtools.com/handbook/how-to/how-to-upgrade-uv.md)
- [src layout vs flat layout: which to use and why](https://pydevtools.com/handbook/explanation/src-layout-vs-flat-layout.md)
- [What is a build backend?](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md)
- [uv 0.12.0 release notes](https://github.com/astral-sh/uv/releases/tag/0.12.0)
