# src layout vs flat layout: which to use and why


A packaging mistake can pass every local [pytest](https://pydevtools.com/handbook/reference/pytest.md) run and still break in production. The choice between flat layout and src layout decides whether your tests catch it before users do.

## Compare the two layouts

Flat layout places the package directory directly at the project root:

{{< /filetree/folder >}}
    {{< /filetree/folder >}}
  {{< /filetree/folder >}}
{{< /filetree/container >}}

Src layout nests the package under a `src/` directory:

{{< /filetree/folder >}}
    {{< /filetree/folder >}}
    {{< /filetree/folder >}}
  {{< /filetree/folder >}}
{{< /filetree/container >}}

The only structural difference is the `src/` wrapper. Every other file, including [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md) and `tests/`, stays at the project root in both cases.

## How the flat layout masks packaging bugs

When you run `pytest` from the project root, Python adds `.` (the current directory) to `sys.path`. In a flat layout, `import mypackage` resolves to the local directory, not the installed package. Tests run against the raw source files.

This works fine until something breaks in production but not in your tests. Common failures that flat layout hides:

- A file missing from the package's `include` configuration still imports from the local directory, so tests pass while the published wheel is broken.
- A misconfigured package name in `pyproject.toml` only fails after installation, not during development.
- Data files (templates, config files) included by local path in development but absent from the built wheel cause errors only on the user's machine.
- A renamed module that still resolves locally because the stale file lingers in the working directory after a refactor.

The src layout closes this gap. Because `src/` is not on `sys.path` by default, `import mypackage` raises `ModuleNotFoundError` unless the package is installed. Running [uv sync](https://pydevtools.com/handbook/reference/uv.md) installs it in [editable mode](https://pydevtools.com/handbook/explanation/what-is-an-editable-install.md), so tests run against the installed version and catch these mistakes before publication.

## See what uv init writes for each project type

`uv init` chooses a layout based on what you are building:

| Command | Layout | Build system | Use case |
|---|---|---|---|
| `uv init` (default) | Flat | No | Web apps and internal tools you run directly |
| `uv init --lib` | Src | Yes | Reusable libraries |
| `uv init --package` | Src | Yes | Distributable CLI tools |

Applications you run directly with `uv run` do not need a [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md) and benefit from the flat layout's simplicity. Libraries and CLI tools you publish to [PyPI](https://pydevtools.com/handbook/explanation/what-is-pypi.md) benefit from the src layout's packaging guarantees.

See [uv init: project types, flags, and examples](https://pydevtools.com/handbook/explanation/understanding-uv-init-project-types.md) for a full breakdown of each flag.

## Choose the right layout

Use the **src layout** when:
- Building a library or CLI you plan to publish to PyPI
- You want tests to validate the installed package, not raw source files

Use the **flat layout** when:
- Building an application you run directly with `uv run` and never publish
- Adding uv to an existing project with its own established structure

When uncertain, prefer the src layout. It catches packaging mistakes before they reach users, and `uv init --lib` or `uv init --package` set up the configuration for you.

## Learn more

- [uv init: project types, flags, and examples](https://pydevtools.com/handbook/explanation/understanding-uv-init-project-types.md)
- [What is a build backend?](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md)
- [Publish your first Python package to PyPI](https://pydevtools.com/handbook/tutorial/publishing-your-first-python-package-to-pypi.md)
- [PyPA discussion: src layout vs flat layout](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/)
- [Hynek Schlawack: Testing and packaging](https://hynek.me/articles/testing-packaging/)
