Your Python project structure, also known as your project layout, is the arrangement of files and directories that determines how your code gets imported, tested, and packaged. Choosing between a flat and a src/ layout depends on the type of project you’re building and the trade-offs you accept.
In this tutorial, you’ll turn those choices into confident defaults for libraries and for CLI, web, and GUI applications.
By the end of this tutorial, you’ll understand that:
- The type of project you build, whether a script, an application, or a library, points to the layout that fits.
- A flat layout keeps the importable package at the project root, so you can import it without installing anything.
- A
src/layout hides the package behind an install step, so your tests exercise the same code your users receive. - A thin
__main__.pypaired with a[project.scripts]table inpyproject.tomlis the modern way to define the project’s entry point, and it replaces older approaches likesetup.pyor abin/directory. - Domain-named subpackages like
core/andapi/scale better than catch-all modules likeutils.py.
To follow along, it helps if you’re comfortable with Python modules and packages and if you’ve run a script or two from the command line.
You won’t install anything or build a full application here. Instead, several annotated directory trees will show you why each file belongs where it does.
Get Your Cheat Sheet: Click here to download your free Python project structure cheat sheet and keep the flat vs. src/ decision and the entry-point wiring within reach on your next project.
Take the Quiz: Test your knowledge with our interactive “Python Project Structure: How to Choose the Right Layout” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python Project Structure: How to Choose the Right LayoutTest your understanding of Python project structure, from flat and src layouts to organizing packages for CLI, web, and GUI applications.
Understanding Why Python Project Structure Matters
A directory layout can feel like bookkeeping, but it shapes every interaction that you and your teammates have with the code. The payoff of a clear layout shows up in several concrete ways, including the following:
- Lower cognitive load: When every file sits in a descriptively named directory and has a name that signals what it holds, a contributor who opens the repository for the first time can guess where things live instead of grepping around.
- Predictable imports: When your directories mirror the way you import them, you can read a module’s dotted import name straight off the directory tree rather than hunting for where it lives.
- Reliable tests: When your tests find the package and modules just as your users will, running
pytestbehaves the same in continuous integration (CI) as it does on your computer. - Smooth packaging: When you ship a library to PyPI, build a CLI binary, deploy a web service in a container, or freeze a desktop app with PyInstaller, the right layout means the wheel, installer, or image holds exactly what you expect. You end up with no missing assets, no stowaway test files, and no broken entry points.
All of these benefits rest on a vocabulary distinction worth getting straight early. The project is the whole repository, including its configuration, tests, and documentation. The package is the importable code that lives inside the project. Keeping the two ideas separate makes the rest of this tutorial click into place because most layout questions come down to where the package sits relative to everything else.
If you want a refresher on the import machinery behind these ideas, then the project layout reference makes a good companion. With the vocabulary in hand, you can start narrowing your options by naming the type of project that you’re building.
Identifying the Type of Project You’re Building
Before you start learning about layouts, you need to know what you’re laying out. Python projects fall into three broad types, and each one has its own typical layout:
- Scripts: One or a few
.pyfiles that you run directly. They need no installation and often nopyproject.toml, or at most a PEP 723 inline header. A data-cleanup script or acronjob fits here. - Applications: Software that you run or deploy, rather than code that others import. This is where Python application structure varies the most, covering CLIs, web apps, GUI apps, and background workers. Web apps use frameworks like Django, Flask, or FastAPI, while GUI apps rely on tools like PyQt, Tkinter, Toga, or Kivy. You ship them as a container, a wheel, or an installer.
- Libraries: Importable code that other projects depend on. You can distribute a library through PyPI, and your users consume it with
import package_name. Familiar examples include requests, HTTPX, and Rich.
A couple of cases sit at the edges of this taxonomy and could cause confusion:
- A plugin, like
pytest-cov, is a specialized library that gets consumed through a[project.entry-points]table inpyproject.tomlinstead of a directimport. - A hybrid, like
pytest,mypy, orblack, ships as both a library and a command-line tool. The structural rule is to build the project around the more demanding half, usually the library, and then add the CLI as a thincli.pywith a[project.scripts]entry.
Naming the project type is the first step of the layout decision because the type alone points you to a default you can adopt unless you have a reason not to:
| Project Type | Typical Layout | Why |
|---|---|---|
| Scripts | None (flat if it grows) | A script is barely a project, and a flat layout with pyproject.toml is the natural next step. |
| Applications | Flat | Most web frameworks scaffold projects flat, and you switch to src/ when packaging or wheel deployment matters. |
| Libraries | src/ | Installation is part of the user contract, since you mostly distribute through PyPI or a private index. |
This table shows where you’ll end up. Here’s a short, repeatable workflow that you’ll follow throughout the rest of this tutorial:
- Identify the type of Python project.
- Pick a layout.
- Organize the package from the inside out.
Those three steps will guide your decision-making, starting with the type of project you’re building and the layout it points to:
With the project type settled, take a closer look at the two main layouts that cover nearly every Python project.
Read the full article at https://realpython.com/python-application-layouts/ »
[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

