September 13, 2026
3 min read
FastAPI — Production Patterns
Project Structure
app/
├── main.py # FastAPI app, lifespan, router includes
├── config.py # Pydantic Settings
├── database.py # engine, session factory, get_db
├── models/ # SQLAlchemy ORM models
├── schemas/ # Pydantic request/response models
├── api/ # routers (thin HTTP layer)
├── services/ # business logic
└── repositories/ # DB access layer
Layer
Responsibility
api/
HTTP only — parse request, call service, return response
services/
Business logic, orchestration, validation rules
repositories/
Database queries, ORM operations
schemas/
Input/output contracts (Pydantic)
models/
DB table definitions (SQLAlchemy)
Configuration with Pydantic Settings
from functools import lru_cache
from pydantic_settings import BaseSettings , SettingsConfigDict
class Settings ( BaseSettings ):
model_config = SettingsConfigDict ( env_file = ".env" , env_file_encoding = "utf-8" )
app_name : str = "My Service"
debug : bool = False
database_url : str
secret_key : str
access_token_expire_minutes : int = 30
@lru_cache
def get_settings () -> Settings :
return Settings ()
@lru_cache ensures settings are loaded once. Inject via Depends(get_settings).
Background Tasks
from fastapi import BackgroundTasks , FastAPI
app = FastAPI ()
async def send_welcome_email ( email : str ):
...
@app . post ( "/users" )
async def create_user ( email : str , background_tasks : BackgroundTasks ):
background_tasks . add_task ( send_welcome_email , email )
return { "message" : "User created, email will be sent" }
Use case
Tool
Quick fire-and-forget
BackgroundTasks (built-in)
Heavy/long-running jobs
Celery, ARQ, or Dramatiq
Scheduled tasks
APScheduler or Celery Beat
WebSocket
from fastapi import FastAPI , WebSocket , WebSocketDisconnect
app = FastAPI ()
class ConnectionManager :
def __init__ ( self ):
self . active : list [ WebSocket ] = []
async def connect ( self , ws : WebSocket ):
await ws . accept ()
self . active . append ( ws )
def disconnect ( self , ws : WebSocket ):
self . active . remove ( ws )
async def broadcast ( self , message : str ):
for conn in self . active :
await conn . send_text ( message )
manager = ConnectionManager ()
@app . websocket ( "/ws/ {room} " )
async def websocket_endpoint ( ws : WebSocket , room : str ):
await manager . connect ( ws )
try :
while True :
data = await ws . receive_text ()
await manager . broadcast ( f "[ { room } ] { data } " )
except WebSocketDisconnect :
manager . disconnect ( ws )
Error Handling & Logging
import logging
from fastapi import FastAPI , Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
logger = logging . getLogger ( "app" )
@app . exception_handler ( RequestValidationError )
async def validation_handler ( request : Request , exc : RequestValidationError ):
return JSONResponse ( status_code = 422 , content = { "error" : "validation" , "detail" : exc . errors ()})
@app . middleware ( "http" )
async def log_requests ( request : Request , call_next ):
logger . info ( "→ %s %s " , request . method , request . url . path )
response = await call_next ( request )
logger . info ( "← %s %d " , request . url . path , response . status_code )
return response
Health Checks
from fastapi import Depends , FastAPI
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
app = FastAPI ()
# get_db is an app dependency that yields AsyncSession.
@app . get ( "/health" )
async def liveness ():
return { "status" : "ok" }
@app . get ( "/health/ready" )
async def readiness ( db : AsyncSession = Depends ( get_db )):
await db . execute ( text ( "SELECT 1" ))
return { "status" : "ready" }
Endpoint
Purpose
/health
Liveness — is the process running?
/health/ready
Readiness — are dependencies available?
Deployment
FROM python:3.13-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync --frozen --no-dev
COPY app/ app/
CMD [ "uvicorn" , "app.main:app" , "--host" , "0.0.0.0" , "--port" , "8000" , "--workers" , "4" ]
services :
api :
build : .
ports : [ "8000:8000" ]
env_file : [ .env ]
depends_on : { db : { condition : service_healthy } }
db :
image : postgres:17
environment : { POSTGRES_DB : mydb , POSTGRES_USER : user , POSTGRES_PASSWORD : pass }
healthcheck : { test : [ "CMD-SHELL" , "pg_isready -U user" ], interval : 5s , retries : 5 }
Setting
Dev
Production
--reload
Yes
No
--workers
1
CPU cores × 2 + 1
--log-level
debug
info
Reverse proxy
None
Nginx / Traefik
HTTPS
Optional
Required
api
fastapi
libraries
python