HOWTO · Python
Project Structure for a Python Application
Learn how to structure a Python Application
On this page
A maintainable Python project keeps its root focused, groups related code into packages, and adds supporting folders only when the application needs them. Choose the layout based on how the program runs; a modular application can still be deployed as one small monolith.
Choose a layout that fits your application
A clear project layout makes code easier to find, maintain, and share with collaborators. It does not require splitting a program into microservices. A small application can remain a single deployable program while its related code is grouped into modules and packages. Add directories when they give the project a useful boundary; avoid creating empty folders just to imitate a larger project’s structure.
The right layout depends on how the application runs and what it contains. A command-line tool may need only application code, dependency information, and tests. A web application may also need templates and static assets. A project that uses SQLite may create a local database file, while one connected to a database service usually keeps that data outside the source tree.
Start with the project root
The project root is the directory that holds the files used to develop, test, document, and package the application. Common choices include a README.md with setup and usage instructions, a LICENSE that states how others may use and distribute the code, and a dependency declaration such as pyproject.toml or requirements.txt. These files serve different purposes; a project does not need every packaging or dependency format.
Python applications do not share one required entry-point filename. A command-line program might be launched with python -m package_name, while a framework or packaging configuration can define another command. Use the launch method that fits the application instead of assuming every project needs run.py or setup.py.
Create a virtual environment locally to isolate the project’s installed packages. Keep it out of version control; collaborators can create their own from the dependency information. A .gitignore file commonly excludes that environment along with caches and other generated files. The root can stay compact: add documentation or packaging configuration as the project needs them.
Organize application code into packages
Group Python modules by responsibility. For example, a blog might keep account-related code in users and post-related code in posts. This is ordinary in-process organization: both packages can run as parts of one application and do not need to communicate as independent services.
A regular package commonly includes an __init__.py file. It can be empty, or it can expose selected names as part of the package interface. Python also supports namespace packages that can omit this file, so follow the package style and tooling chosen for the project rather than treating __init__.py as universal. Put shared code in a module or package when multiple parts use it, and avoid duplicating the same behavior across folders.
Add tests, documentation, and web resources when needed
A tests directory keeps automated checks separate from application code. Tests are useful even in small projects: they make expected behavior easier to verify as the code changes. A docs directory can hold longer user or contributor guidance when a README is no longer enough.
Web projects often have a templates directory for HTML rendered by the application and a static directory for assets such as CSS, JavaScript, and images. Their exact locations depend on the framework and its configuration. A non-web command-line application usually has no reason to include them.
Database models belong wherever they fit the chosen architecture; a project may use a dedicated module such as models.py or a package for several model groups. A file such as database.db is appropriate only when the application actually uses a local file-based database, for example SQLite. Do not add a database file to the source layout merely because the application stores data elsewhere.
Example: a small blog application
This blog keeps its account and post code in separate packages, and places web-only resources and project support files at the root. The tree is a starting point: framework conventions may place templates, models, or static files differently. The database file is shown for a local SQLite setup, and the local virtual environment is intentionally left out of the tracked project layout.
Run this example:
layout = [
"blog/",
"├── README.md",
"├── LICENSE",
"├── pyproject.toml",
"├── blog/",
"│ ├── __init__.py",
"│ ├── users/",
"│ └── posts/",
"├── templates/",
"├── static/",
"├── tests/",
"└── database.db (local SQLite only)",
]
print("\n".join(layout))
blog/
├── README.md
├── LICENSE
├── pyproject.toml
├── blog/
│ ├── __init__.py
│ ├── users/
│ └── posts/
├── templates/
├── static/
├── tests/
└── database.db (local SQLite only)
The tree keeps deployment configuration and framework details out of the example, so adapt it to the toolchain you use. Add files such as models.py inside the package that owns the data behavior, or expand a package when it grows. For a command-line project, omit the web folders; for a database service, omit the local database file. Keep the same principle as the project evolves: each directory should help a reader locate related code or resources.