This content originally appeared on DEV Community and was authored by Zaenal Arifin
When you first start with FastAPI, itβs tempting to throw everything into a single file β and it works fineβ¦ until your app grows. Then suddenly, your codebase becomes spaghetti.
In this post, weβll go through how to structure a FastAPI project properly, using clean architecture principles that scale easily.
  
  
  
 Why Project Structure Matters
A good structure makes your project:
- Easier to maintain and scale.
 - Easier for new developers to understand.
 - Ready for testing, CI/CD, and deployment.
 
If your FastAPI project looks like this:
main.py
models.py
routes.py
schemas.py
database.py
β¦itβs time for an upgrade.
  
  
  
 Recommended Folder Structure
Hereβs a clean, production-ready structure I use for real projects:
app/
βββ api/
β   βββ routes/
β   β   βββ users.py
β   β   βββ items.py
β   β   βββ __init__.py
β   βββ deps.py
β   βββ __init__.py
β   βββ api_v1.py
βββ core/
β   βββ config.py
β   βββ security.py
β   βββ __init__.py
βββ db/
β   βββ base.py
β   βββ session.py
β   βββ __init__.py
βββ models/
β   βββ user.py
β   βββ item.py
β   βββ __init__.py
βββ schemas/
β   βββ user.py
β   βββ item.py
β   βββ __init__.py
βββ services/
β   βββ user_service.py
β   βββ __init__.py
βββ main.py
βββ __init__.py
  
  
  
 Letβs Break It Down
  
  
  core/
Contains global configurations β environment variables, security settings, and constants.
# app/core/config.py
from pydantic import BaseSettings
class Settings(BaseSettings):
    APP_NAME: str = "My FastAPI App"
    DATABASE_URL: str
    class Config:
        env_file = ".env"
settings = Settings()
  
  
  db/
Handles all database setup β connection, session management, and base models.
# 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(bind=engine, autocommit=False, autoflush=False)
  
  
  api/routes/
Organize endpoints by domain β one file per feature.
# app/api/routes/users.py
from fastapi import APIRouter, Depends
from app.schemas.user import User
from app.services.user_service import get_all_users
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/", response_model=list[User])
async def list_users():
    return await get_all_users()
  
  
  services/
Business logic lives here β keep it separate from routes.
# app/services/user_service.py
from app.db.session import SessionLocal
from app.models.user import User
async def get_all_users():
    db = SessionLocal()
    return db.query(User).all()
  
  
  main.py
The entry point that ties everything together.
# app/main.py
from fastapi import FastAPI
from app.api.api_v1 import api_router
from app.core.config import settings
app = FastAPI(title=settings.APP_NAME)
app.include_router(api_router)
  
  
  
 Tips for Scalable FastAPI Projects
 Use Pydantic models for input/output validation
 Split logic into layers β routes, services, models
 Use dependency injection for clean imports
 Add logging early β donβt debug with print()
 Separate environment variables from code
  
  
  
 Example Repository
Iβve uploaded an example of this structure here:
 GitHub – fastapi-clean-structure (insert your repo link)
You can clone it, install dependencies, and start your app in seconds:
git clone https://github.com/yourusername/fastapi-clean-structure.git
cd fastapi-clean-structure
poetry install
poetry run uvicorn app.main:app --reload
  
  
  
 Conclusion
Clean project structure isnβt just about being βorganizedβ β itβs about future-proofing your codebase.
FastAPI makes things fast, but structure makes them sustainable.
If you found this useful, drop a 
 or follow me β I post about Python, FastAPI, and backend architecture regularly.
This content originally appeared on DEV Community and was authored by Zaenal Arifin