Fast Project Structure
Scaling a FastAPI project means moving from a single main.py file to a well-organized, modular folder structure.
Large-Scale FastAPI Project Structure
Section titled βLarge-Scale FastAPI Project StructureβHereβs a recommended structure used in production-grade FastAPI apps:
project/βββ app/β βββ __init__.pyβ βββ main.py # FastAPI app entrypointβ βββ core/ # Core configurationβ β βββ __init__.pyβ β βββ config.py # Settings (env vars, DB URL, etc.)β β βββ security.py # JWT / Auth utilsβ β βββ logging.py # Logging configβ ββ βββ api/ # API routesβ β βββ __init__.pyβ β βββ deps.py # Shared dependencies (Depends)β β βββ v1/ # Versioned APIsβ β β βββ __init__.pyβ β β βββ routes_users.pyβ β β βββ routes_items.pyβ β β βββ routes_auth.pyβ β βββ v2/ # Future APIsβ ββ βββ models/ # SQLAlchemy / Pydantic modelsβ β βββ __init__.pyβ β βββ user.pyβ β βββ item.pyβ ββ βββ schemas/ # Pydantic schemasβ β βββ __init__.pyβ β βββ user.pyβ β βββ item.pyβ ββ βββ services/ # Business logicβ β βββ __init__.pyβ β βββ user_service.pyβ β βββ item_service.pyβ ββ βββ db/ # Database session & migrationsβ β βββ __init__.pyβ β βββ base.py # Base metadataβ β βββ session.py # SQLAlchemy SessionLocalβ β βββ init_db.pyβ ββ βββ tests/ # Unit & integration testsβ β βββ __init__.pyβ β βββ test_auth.pyβ β βββ test_users.pyβ β βββ conftest.pyβ ββ βββ utils/ # Helper functionsβ βββ __init__.pyβ βββ email.pyβ βββ hashing.pyββββ alembic/ # Migrations (if using Alembic)βββ .env # Environment variablesβββ requirements.txtβββ pyproject.tomlβββ Dockerfileβββ docker-compose.ymlExplanation of Each Layer
Section titled βExplanation of Each Layerβ1. core/ β Config & Security
Section titled β1. core/ β Config & Securityβ- config.py β Pydantic BaseSettings for environment variables.
- security.py β JWT utils, password hashing.
- logging.py β Centralized logging configuration.
π Keeps global setup separate.
2. api/ β Routers & Dependencies
Section titled β2. api/ β Routers & Dependenciesβ- Organized by version (v1, v2).
- Each module (e.g., users, items) has its own router file.
- deps.py β common dependencies (get_db, get_current_user).
π Encourages modular APIs.
3. models/ & schemas/ β Separation of Concerns
Section titled β3. models/ & schemas/ β Separation of Concernsβ- models/ β SQLAlchemy ORM models (DB representation).
- schemas/ β Pydantic models (input/output validation).
π Keeps DB models separate from request/response models.
4. services/ β Business Logic Layer
Section titled β4. services/ β Business Logic Layerβ- Encapsulates actual logic (e.g., creating users, applying discounts).
- Keeps routers slim β endpoints only orchestrate calls.
5. db/ β Database Session & Migrations
Section titled β5. db/ β Database Session & Migrationsβ- session.py β SQLAlchemy SessionLocal.
- init_db.py β Startup logic (e.g., creating default admin).
6. tests/ β Unit & Integration Tests
Section titled β6. tests/ β Unit & Integration Testsβ- Organized by feature.
- Uses pytest, httpx.AsyncClient.
- conftest.py for fixtures (e.g., test DB session).
7. utils/ β Reusable Helpers
Section titled β7. utils/ β Reusable Helpersβ- Utility functions (e.g., hashing, sending emails, formatting).
Example Code Snippets
Section titled βExample Code Snippetsβcore/config.py
Section titled βcore/config.pyβfrom pydantic import BaseSettings
class Settings(BaseSettings): PROJECT_NAME: str = "My FastAPI App" DATABASE_URL: str SECRET_KEY: str ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
class Config: env_file = ".env"
settings = Settings()db/session.py
Section titled βdb/session.pyβfrom sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmakerfrom app.core.config import settings
engine = create_engine(settings.DATABASE_URL, future=True, echo=True)SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)api/v1/routes_users.py
Section titled βapi/v1/routes_users.pyβfrom fastapi import APIRouter, Dependsfrom sqlalchemy.orm import Sessionfrom app.db.session import SessionLocalfrom app.schemas.user import UserCreate, UserOutfrom app.services.user_service import create_user
router = APIRouter()
def get_db(): db = SessionLocal() try: yield db finally: db.close()
@router.post("/users", response_model=UserOut)def register_user(user: UserCreate, db: Session = Depends(get_db)): return create_user(db, user)services/user_service.py
Section titled βservices/user_service.pyβfrom sqlalchemy.orm import Sessionfrom app.models.user import Userfrom app.schemas.user import UserCreatefrom app.utils.hashing import hash_password
def create_user(db: Session, user: UserCreate): db_user = User(username=user.username, hashed_password=hash_password(user.password)) db.add(db_user) db.commit() db.refresh(db_user) return db_userπ Best Practices
Section titled βπ Best Practicesββ
Use versioned APIs (/api/v1, /api/v2).
β Keep models, schemas, services, and routes separate.
β
Use Dependency Injection (Depends) for DB sessions, security.
β Write unit & integration tests for each module.
β Use Alembic for migrations.
β
Use .env for secrets, never hardcode credentials.
β Use Docker & docker-compose for reproducible environments.
β Add logging & monitoring early.