A production-ready FastAPI template designed for building secure, scalable APIs with modern best practices baked in. This template provides a robust foundation for enterprise-grade applications, featuring essential security measures, performance optimizations, and maintainable architecture patterns out of the box.
- JWT Authentication with refresh tokens π
- Custom Rate Limiting per user/service β±οΈ
- Unified Logging (UVICORN + GUNICORN) π
- Redis Connection Pooling (Async) with fail-open strategy π§
- PostgreSQL Connection Pooling (Async) with health checks π
- Standardized API Responses π¦
- Alembic for Database Migrations ποΈ
- Modern Package Management with
uvβ‘ - Production-Ready Error Handling π‘οΈ
- Docker + Gunicorn + Uvicorn Stack π³β‘
- OpenTelemetry Observability β metrics, traces, Golden Signals dashboards (Prometheus + Grafana + Tempo) π
This template includes a production-grade OpenTelemetry observability setup designed for real-world systems:
- Automatic FastAPI instrumentation
- Distributed tracing with Tempo
- Golden Signals dashboards in Grafana
- Prometheus metrics via OpenTelemetry
- Custom application & rate-limiter visibility
π All observability details live here: π docs/OBSERVABILITY.md
| Component | Technology |
|---|---|
| Framework | FastAPI 0.111+ |
| Database | PostgreSQL 14+ |
| Cache | Redis 6+ |
| ORM | SQLAlchemy 2.0 |
| Migrations | Alembic |
| Authentication | JWT (OAuth2 Password Bearer) |
| Rate Limiting | Redis-backed Custom Implementation |
| Package Manager | uv (fast Python installer) |
| Containerization | Docker |
| Observability | OpenTelemetry |
The repository follows a modular, domain-oriented structure designed for large, production-grade FastAPI applications:
-
app/β Core FastAPI application- Domain modules (
user,todo,health) - Core configuration, database, logging (
core/) - Shared utilities: auth dependency, rate limiter (
utils/) - OpenTelemetry observability setup (
observability/) - Alembic migrations
- Application entry point (
main.py)
- Domain modules (
-
docker/observability/β Local observability stack- OpenTelemetry Collector
- Prometheus
- Grafana (pre-provisioned dashboards & datasources)
- Tempo (distributed tracing)
-
docs/β Documentation & assets- Observability guide and dashboards
- Architecture diagrams and screenshots
-
tests/β Automated tests -
Root files β
Dockerfile,Makefile,run.sh,pyproject.toml,uv.lock, etc.
PostgreSQL (SQLAlchemy 2.0 + asyncpg):
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
# Async PostgreSQL connection pool
engine = create_async_engine(
"postgresql+asyncpg://user:pass@host:port/dbname",
pool_size=20, # Persistent connection pool size
max_overflow=10, # Temporary connections beyond pool_size
pool_recycle=300, # Recycle connections every 300s
pool_pre_ping=True, # Validate connections before use
future=True # Enable SQLAlchemy 2.0 behavior
)
# Async session factory configuration
AsyncSessionLocal = async_sessionmaker(
bind=engine,
expire_on_commit=False, # Prevent attribute expiration on commit
autoflush=False, # Manual flush control
class_=AsyncSession # Use SQLAlchemy's async session class
)Key Features:
- π Full Async Support: Non-blocking database operations via asyncpg
- π Connection Recycling: Prevents stale connections in long-running applications
- π©Ί Connection Validation: Pre-ping checks verify connection health
- π Optimized Pooling: Balances memory usage and concurrent requests
- β‘ SQLAlchemy 2.0: Future-proof API with explicit transaction control
Redis Connection Pool:
redis = await Redis(
host="redis.prod.internal",
port=6379,
db=0,
password="securepassword",
socket_connect_timeout=5, # 5s connection timeout
socket_keepalive=True, # Maintain TCP keepalive
retry_on_timeout=True, # Auto-retry failed operations
max_connections=100, # Max pool size
health_check_interval=30 # Validate connections every 30s
)- Enterprise Features: TLS support, cluster mode ready
- Resiliency: Automatic retries and health checks
Protected Todo Creation:
@router.post("/")
async def create_todo(
body: TodoCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
"""
Implements:
- JWT Authentication
- User-based Rate Limiting
- Structured Error Handling
- Audit Logging
"""
try:
# Rate limit check
await user_rate_limiter(current_user.user_id, "todo_write")
# Business logic
data = await create_todo_service(current_user.user_id, body, db)
# Standardized success response
return {
"status": "success",
"message": "Todo created",
"data": data
}
except HTTPException as e:
# Preserve existing HTTP exceptions
raise
except Exception as e:
# Log full error context
logger.error(f"Todo creation failed: {str(e)}", exc_info=True)
# Return standardized error format
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal server error"
)Implementation:
async def user_rate_limiter(
user_id: str,
service: str,
times: int = 5,
seconds: int = 60
):
"""
Redis-backed rate limiter using LUA scripts for atomic operations
"""
key = f"rl:user:{user_id}:{service}"
try:
pexpire = await FastAPILimiter.redis.evalsha(
FastAPILimiter.lua_sha, 1,
key,
str(times),
str(seconds * 1000) # Convert to milliseconds
)
if pexpire != 0:
raise HTTPException(
status_code=429,
detail=f"Try again in {ceil(pexpire/1000)} seconds"
)
except Exception as e:
logger.error(f"Rate limit check failed: {str(e)}")
# Fail-open during Redis outagesFeatures:
- β User+service specific limits
- β Atomic Redis operations via LUA scripts
- β Fail-open circuit breaker pattern
- β Millisecond precision timeouts
- β Automatic retry-after calculation
Configuration:
logging_config = {
"version": 1,
"formatters": {
"standard": {
"format": "[{asctime}] [{process}] [{levelname}] {module}.{funcName}:{lineno} - {message}",
"datefmt": "%Y-%m-%d %H:%M:%S %z",
"style": "{"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "standard",
"stream": "ext://sys.stdout"
}
},
"loggers": {
"": {"level": "DEBUG", "handlers": ["console"], "propagate": False},
"uvicorn": {"level": "INFO", "propagate": False},
"uvicorn.access": {"level": "INFO", "propagate": False},
"uvicorn.error": {"level": "INFO", "propagate": False}
}
}Log Example:
[2024-05-20 14:30:45 +0000] [1234] [INFO] todo.routers.create_todo:52 - Created todo ID:42
Features:
- π Consistent timestamp with timezone
- π Process ID tracking
- π Module/function/line number context
- π Uvicorn log unification
- π Production-ready INFO level defaults
Success Response:
{
"status": "success",
"message": "Todo created successfully",
"data": {
"id": 42,
"task": "Implement rate limiting"
}
}Error Response:
{
"status": "error",
"message": "Validation Failed",
"errors": [
{
"type": "missing",
"loc": ["body", "task"],
"msg": "Field required",
"input": {}
}
]
}Implementation:
@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
errors = [
{"type": e.get("type"), "loc": e.get("loc"), "msg": e.get("msg"), "input": e.get("input")}
for e in exc.errors()
]
return JSONResponse(
status_code=422,
content={
"status": "error",
"message": "Validation Failed",
"errors": errors,
}
)
@app.exception_handler(HTTPException)
async def http_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={
"status": "error",
"message": exc.detail,
"errors": getattr(exc, "errors", None),
}
)Features:
- β RFC-compliant error formats
- β Automatic validation error parsing
- β Consistent error code mapping
- β Detailed error context preservation
- Python 3.11+
- PostgreSQL 14+
- Redis 6+
- Docker (optional)
git clone https://github.com/akhil2308/fastapi-large-app-template.git
cd fastapi-large-app-template
# Install uv (if not already installed)
pip install uv
# Sync dependencies and create virtual environment
# This installs all packages defined in pyproject.toml
uv sync --all-extras
# Install Git Hooks
# This ensures code quality checks run automatically on commit
uv run pre-commit installThis project includes a Makefile with convenient commands. Run make help to see all available targets.
# Show all available commands
make help
# Install dependencies and setup git hooks
make install
# Development server
make dev
# Production server
make prod
# Run tests
make test
# Database migrations
make migrate
make migrate-create MSG="your migration message"
# Code quality
make check-env
make lint
make format
make typecheck
# Full CI pipeline
make ci
# Clean generated files
make cleancp .env.example .env
# Fill in DB, Redis, JWT, and other valuesGenerate new migration:
uv run alembic -c app/alembic.ini revision --autogenerate -m "message"Apply migrations:
uv run alembic -c app/alembic.ini upgrade headDevelopment:
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000Production:
./run.sh # Starts Gunicorn with Uvicorn workersThis project enforces code quality using Ruff (linter/formatter) and Mypy (static type checker).
1. Linting & Formatting (Ruff)
# See what code Ruff wants to fix (Dry Run)
uv run ruff check .
# Actually fix the code (Auto-formatting & Import sorting)
uv run ruff check . --fix
uv run ruff format .2. Static Type Checking (Mypy)
# Check for type errors
uv run mypy .Note: π A pre-commit hook is configured. When you attempt to
git commit, these checks will automatically run to ensure no bad code is pushed to the repository.
Access interactive docs after starting server:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc - OpenAPI:
http://localhost:8000/openapi.json
See CONTRIBUTORS.txt for contribution guidelines and code of conduct.
This project is licensed under the MIT License - see LICENSE for details.