Folder Structure Matters: My Python Project Template Explained

Here’s the folder structure I use to keep my Python projects clean, scalable, and ready for production — plus why it works.

Folder Structure Matters: My Python Project Template Explained
Photo by Clay Banks on Unsplash

Most Python projects don’t fail because of bad code — they fail because they’re impossible to maintain.

Folder Structure Matters: My Python Project Template Explained

If there’s one thing that separates beginner code from professional-grade software, it’s structure.

Over the years, I’ve worked on everything from quick scripts to full-blown production systems in Python.

And no matter the size of the project, one lesson stands out:

Your folder structure is not just about organizing files — it’s about scaling sanity.

In this article, I’ll walk you through the Python project template I’ve honed through trial, error, and late-night refactors.

It’s simple, scalable, and battle-tested.


My Go-To Python Project Template

Here’s the folder structure I use for almost every Python project — from APIs to CLI tools:

my_project/ 
│ 
├── src/                    
│   └── my_project/        ← Application code lives here 
│       ├── __init__.py 
│       ├── config.py 
│       ├── main.py 
│       ├── utils/ 
│       │   └── __init__.py 
│       └── modules/ 
│           ├── __init__.py 
│           ├── auth.py 
│           └── data.py 
│ 
├── tests/                 ← Unit and integration tests 
│   ├── __init__.py 
│   └── test_main.py 
│ 
├── .env                   ← Environment variables 
├── .gitignore              
├── pyproject.toml         ← Project metadata and dependencies 
├── README.md               
└── requirements.txt       ← (optional) Pinned dependencies for pip users

Inside the Structure

1. src/ and the Double Folder Trick

Putting your actual app inside src/ and then a second my_project/ inside it seems redundant, but here’s why I do it:

  • It prevents import shadowing. With this pattern, running tests from the root won’t mistakenly import files from the wrong places.
  • It clearly separates source code from test, config, and infra files.

Set your PYTHONPATH to src/ in dev environments.

2. config.py: Centralized Settings

All environment-based settings go here — API keys, database URLs, debug flags.

You can load them with os.getenv() or a library like pydantic.

import os 
 
DEBUG = os.getenv("DEBUG", "False") == "True" 
DATABASE_URL = os.getenv("DATABASE_URL")

3. modules/: Group Features by Responsibility

Rather than lumping everything into a single file, I split features into modules — e.g., auth.py, data.py, analytics.py.

Each module does one thing.

This makes the code easier to test, debug, and reuse.

4. utils/: Common Helpers

Utility functions that are reused across the project — like date formatting, error handling, or logging — go here.

If a utility grows too large, I break it into smaller files within utils/.

5. tests/: Your Safety Net

Tests mirror the structure of my_project/.

Each module has a corresponding test file.

I use pytest for simplicity, readability, and speed.

pytest tests/

6. pyproject.toml: One File to Rule Them All

This is the future of Python packaging and configuration. You can define dependencies, formatters, and linters all in one place.

Here’s a minimal pyproject.toml with Poetry:

[tool.poetry] 
name = "my_project" 
version = "0.1.0" 
description = "Awesome Python project" 
authors = ["You <you@example.com>"] 
 
[tool.poetry.dependencies] 
python = "^3.10" 
 
[build-system] 
requires = ["poetry-core"] 
build-backend = "poetry.core.masonry.api"

Development Workflow Tips

  • Use virtual environments (venv, poetry shell, or uv) to isolate dependencies.
  • Stick to a naming convention for modules and functions.
  • Adopt type hints and a linter (ruff, flake8, or black) early.
  • Consider using pre-commit hooks to auto-format and lint before every commit.
  • Document your decisions in the README.md for future-you (and your team).

Bonus: Making It a Template

Want to reuse this structure for every project?

You can:

  1. Zip it and keep a local starter template.
  2. Use GitHub’s template repo feature.
  3. Automate with Cookiecutter to scaffold new projects in seconds.

Final Thoughts

You don’t need a fancy structure to start coding. But if you want to grow confidently, collaborate with others, and deploy without pain — your project layout matters.

This template has saved me from countless hours of confusion and refactoring.

I hope it saves you too.

If you liked this breakdown, feel free to bookmark it and customize the template to fit your workflow.


Want more articles like this? Follow me on Medium and check out:

Why I Stopped Using Monoliths for My Python Projects
Discover why I broke my Python monoliths into modular components — and how it transformed my development speed and code…
This One Habit Made My Python Code 3× Faster
Discover the single optimization mindset that helped me write more efficient Python code — without sacrificing…
I Stopped Writing Comments and My Python Code Got Better — Here’s Why
Here’s how ditching excessive comments pushed me to write more readable, self-documenting Python — and why you might…
Photo by Simone Hutsch on Unsplash