Project Layout in Python: Why the `src/` Structure Matters
Many Python projects start with files in the root directory. The `src/` layout may feel unnecessary at first, but it prevents subtle import bugs and prepares your project for packaging and testing.
The Problem Most Developers Do Not Notice
When starting a Python project, it is common to place everything in the root directory:
my_project/
├── main.py
├── utils.py
├── config.py
It works.
Until it does not.
As soon as you introduce testing, packaging, or installation, imports can behave differently depending on how the code is executed.
This happens because Python automatically adds the current working directory to sys.path.
That means your project root becomes importable, even if it should not be.
At first, this feels convenient. Later, it becomes fragile.
The Hidden Import Trap
Consider this import:
from utils import helper_function
It works when running from the project root.
But after installing the project as a package, or running tests from another directory, it may fail with:
ImportError: No module named 'utils'
The reason is simple.
Your project was never structured as an installable package.
It only worked because Python was implicitly including the root directory in its import path.
This can mask packaging issues and create situations where it only works locally.
The src/ Layout
The src/ layout separates your source code from the project root:
my_project/
├── src/
│ └── my_package/
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
├── tests/
│ └── test_utils.py
├── pyproject.toml
Now your package lives inside src/, and imports must reference it explicitly:
from my_package import utils
To make everything work consistently, you install the project in editable mode:
pip install -e .
This ensures imports behave the same way in development, testing, and production.
Why the src/ Layout Is Safer
The main benefit is not aesthetics.
It prevents accidental imports from the project root.
If your tests rely on the root directory being on sys.path, they will fail immediately instead of silently passing.
This makes your project:
- More predictable
- Easier to package
- More reliable in CI
- Closer to real production behavior
It forces correctness early.
When You Should Use It
You should strongly consider the src/ layout if:
- You are building a library
- You plan to publish to PyPI
- You have a
pyproject.tomlfile - You maintain automated tests
- The project is expected to grow
For medium to long-term projects, it is usually worth adopting.
When You Do Not Need It
The src/ structure is not mandatory for every scenario.
It may be unnecessary when:
- You are writing a single-file script
- You are experimenting or prototyping
- The project has no packaging or distribution goals
In small throwaway scripts, simplicity matters more than structure.
Final Take
The src/ structure is not about adding complexity.
It is about preventing subtle import issues and aligning development with how packages behave once installed.
For serious projects, it creates discipline and reliability.
For quick scripts, it may be unnecessary.
The key is choosing structure intentionally, not accidentally.