How to Structure Your FastAPI Projects (The Right Way)
Master the art of structuring FastAPI apps like a pro — whether you’re building APIs solo or scaling with a team.

Most FastAPI apps start as a single file… until they don’t.
How to Structure Your FastAPI Projects (The Right Way)
FastAPI has taken the Python web community by storm — and for good reason. It’s fast, intuitive, and perfect for building modern APIs. But as your application grows beyond a few endpoints, structuring your FastAPI project properly becomes absolutely critical.
A well-structured project is easier to maintain, scale, test, and onboard new developers into. In this article, we’ll break down the ideal structure for a FastAPI project and explain why each part exists.
Whether you’re starting a new project or looking to refactor an existing one, this guide has you covered.
The Problem with a “Single File” FastAPI App
Let’s be honest — we’ve all done this:
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, world"}
Simple. Clean. Great for tutorials.
But once you add authentication, database connections, business logic, background tasks, and multiple routers… this file becomes a monolith. It’s no longer maintainable.
The Modular Structure That Just Works
Here’s a recommended folder structure for real-world FastAPI projects:
fastapi_project/
│
├── app/
│ ├── api/
│ │ ├── __init__.py
│ │ ├── deps.py
│ │ ├── v1/
│ │ │ ├── __init__.py
│ │ │ ├── endpoints/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── users.py
│ │ │ │ └── auth.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── security.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py
│ ├── schemas/
│ │ ├── __init__.py
│ │ ├── user.py
│ ├── crud/
│ │ ├── __init__.py
│ │ ├── user.py
│ ├── db/
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── session.py
│ ├── main.py
│
├── tests/
│ ├── __init__.py
│ ├── test_users.py
│
├── requirements.txt
└── README.md
Breaking Down the Components
1. app/api/
: Where Your Routes Live
Organize all your routers by version (e.g., v1
, v2
) and then by feature (e.g., users
, auth
, products
). This keeps your API modular and ready for future versioning.
# app/api/v1/endpoints/users.py
from fastapi import APIRouter, Depends
from app.schemas.user import UserOut
from app.crud.user import get_user
router = APIRouter()
@router.get("/{user_id}", response_model=UserOut)
def read_user(user_id: int):
return get_user(user_id)
2. app/core/
: App-Wide Settings & Security
This includes your configuration logic, JWT security utilities, and any reusable constants.
# app/core/config.py
from pydantic import BaseSettings
class Settings(BaseSettings):
DATABASE_URL: str
SECRET_KEY: str
ALGORITHM: str = "HS256"
class Config:
env_file = ".env"
settings = Settings()
3. app/models/
& app/schemas/
: Your Database and Data Validation Layer
models
: SQLAlchemy models for your DB tables.schemas
: Pydantic models for request and response validation.
# app/schemas/user.py
from pydantic import BaseModel
class UserOut(BaseModel):
id: int
username: str
email: str
class Config:
orm_mode = True
4. app/crud/
: Business Logic and Database Access
Put all your query logic here to keep your endpoints thin and focused.
# app/crud/user.py
from sqlalchemy.orm import Session
from app.models.user import User
def get_user(db: Session, user_id: int):
return db.query(User).filter(User.id == user_id).first()
5. app/db/
: Database Session and Base
Everything related to initializing your SQLAlchemy engine and session management goes here.
# app/db/session.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.core.config import settings
engine = create_engine(settings.DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
6. app/main.py
: The Entry Point
Mount your routers here and wire everything up.
# app/main.py
from fastapi import FastAPI
from app.api.v1.endpoints import users, auth
app = FastAPI()
app.include_router(users.router, prefix="/api/v1/users", tags=["Users"])
app.include_router(auth.router, prefix="/api/v1/auth", tags=["Auth"])
Don’t Skip the tests/
Folder
Testing is not optional in production-grade apps. Structure your test files to mirror your app folder. Use pytest
, mock external dependencies, and aim for at least 80% coverage.
Pro Tips
- Use Dependency Injection: FastAPI shines here. Inject DB sessions, user auth, etc. cleanly using
Depends
. - Environment Management: Use
.env
files +pydantic.BaseSettings
. - Version your APIs from Day 1. It’s much harder to retrofit later.
- Keep endpoints thin — push logic to
crud/
andservices/
. - Dockerize your app for consistent development and deployment.
Final Thoughts
There’s no “one-size-fits-all” structure — but the key is modularity. Your FastAPI project should be easy to navigate, debug, and extend. A solid foundation today prevents pain tomorrow.
Start simple, but think big.
Happy coding
Did you find this helpful? Leave a 👏 or drop your thoughts in the comments — I’d love to hear how you structure your FastAPI apps!
