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 β login, logout (token blacklist) and refresh-token rotation π
- Argon2id Password Hashing via
pwdlibπ - Custom Rate Limiting per user/service, declared as a route dependency β±οΈ
- Unified Logging (UVICORN + GUNICORN) π
- Redis Connection Pooling (Async) with fail-open strategy π§
- PostgreSQL Connection Pooling (Async) with health checks π
- Standardized API Responses with centralized exception handlers π¦
- Typed Settings via
pydantic-settings(fail-fast validation) βοΈ - Alembic for Database Migrations ποΈ
- Modern Package Management with
uvβ‘ - One-command Local Stack β
make up(app + Postgres + Redis) π³ - Kubernetes Manifests β kustomize base + dev/staging/prod overlays, probes, security context, NetworkPolicy, HPA βΈοΈ
- OpenTelemetry Observability β metrics, traces, Golden Signals dashboards (Prometheus + Grafana + Tempo) π
- CI Pipeline β lint, type-check, migration-drift check, tests with coverage gate, Docker build (GitHub Actions, Python 3.11β3.13) β
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.121+ |
| Database | PostgreSQL 14+ |
| Cache | Redis 6+ |
| ORM | SQLAlchemy 2.0 (async, asyncpg) |
| Migrations | Alembic |
| Configuration | pydantic-settings |
| Authentication | JWT (OAuth2 Password Bearer) |
| Password Hashing | Argon2id (pwdlib) |
| Rate Limiting | Redis-backed Custom Implementation |
| Package Manager | uv (fast Python installer) |
| Containerization | Docker + docker-compose |
| Orchestration | Kubernetes (manifests in k8s/) |
| Observability | OpenTelemetry |
| Testing | pytest, fakeredis, hypothesis |
| CI | GitHub Actions (make ci parity) |
The repository follows a layered architecture β each request flows
api β services β crud β models, with schemas for I/O validation. This keeps
HTTP concerns, business logic, and persistence cleanly separated and easy to
test in isolation.
app/
βββ api/ # Routers + request dependencies (user, todo, health)
βββ services/ # Business logic (orchestrates crud + auth)
βββ crud/ # Async SQLAlchemy data-access functions
βββ models/ # SQLAlchemy ORM models
βββ schemas/ # Pydantic request/response schemas
βββ core/ # Settings, database, auth, exceptions, middleware, logging
βββ utils/ # Rate limiter dependency
βββ observability/ # OpenTelemetry telemetry, metrics, instrumentation
βββ alembic/ # Migration environment & versions
βββ main.py # App factory, middleware wiring, exception handlers, lifespan
k8s/ # Kustomize base + dev/staging/prod overlays (deployment, ingress, HPA, NetworkPolicy, migration job)
docker/observability/ # Local Grafana/Tempo/Prometheus/OTel collector stack
docs/ # Observability guide, dashboards, screenshots
tests/ # unit / integration / e2e suites (pytest, fakeredis, hypothesis)
.github/workflows/ # CI: lint, mypy, migrations check, tests + coverage, docker build
docker-compose.yml # One-command local stack (app + postgres + redis)
Dockerfile # Canonical multi-stage image (lockfile-pinned)
These patterns are the reason the template exists. Rather than paste code that drifts from the source, each links to the file that owns it.
| Concern | Where it lives | What to look at |
|---|---|---|
| Typed settings | app/core/settings.py | pydantic-settings tree, validated and fail-fast (e.g. rejects CORS=* with credentials in prod) |
| Async DB pooling | app/core/database.py | create_async_engine + async_sessionmaker, pre-ping, recycle; pool sizes come from settings |
| Redis pool + lifespan | app/main.py | Connection pool, startup health checks, graceful engine.dispose() on shutdown |
| JWT auth | app/core/auth.py, app/api/deps.py | Access/refresh token types, get_current_user, blacklist check |
| Auth flows | app/services/user_service.py | Register / login / logout / refresh-token rotation |
| Rate limiting | app/utils/rate_limiter.py | RateLimit(...) dependency β declared in the route signature, fail-open on Redis errors |
| Centralized errors | app/main.py, app/core/exceptions.py | AppError handlers map domain errors to status codes; routers stay thin |
| Standardized responses | app/core/schemas.py | ApiResponse / PaginatedApiResponse generics |
| Logging | app/core/logging_config.py | Unified Uvicorn/Gunicorn formatter with correlation ID |
| Observability | app/observability/ | OpenTelemetry tracing + metrics; see docs/OBSERVABILITY.md |
Every endpoint returns the same envelope:
{ "status": "success", "message": "...", "data": { ... } }β¦and errors are normalized by the handlers in main.py:
{ "status": "error", "message": "Validation Failed", "errors": [ ... ] }- Python 3.11+
- PostgreSQL 14+
- Redis 6+
- Docker (optional, but the fastest way to run the full stack)
The fastest path β builds the app image and starts the app, PostgreSQL, and Redis together. Migrations run automatically on container start.
make up # build + start app + postgres + redis (detached)
make logs # follow the app logs
make down # stop and remove the stackThen open http://localhost:8000/docs. To also run the observability stack
(Grafana/Tempo/Prometheus/OTel), use make up-observability.
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"
make migrate-check # fail if models drifted from migrations
# Code quality
make check-env
make lint
make format
make typecheck
# Full CI pipeline
make ci
# Local Docker stack (app + postgres + redis)
make up
make down
make logs
# Observability stack (Grafana/Tempo/Prometheus/OTel)
make up-observability
make down-observability
# 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 # Applies migrations, then starts Gunicorn with uvicorn-workerA single canonical multi-stage Dockerfile is used by both
docker-compose and Kubernetes. It installs dependencies straight from uv.lock
with uv sync --frozen (so the image can never drift from the committed lock),
pins the Python base image, and runs as a non-root user.
docker build -t fastapi-large-app-template .Manifests live in k8s/ as a kustomize base + overlays β namespace,
ConfigMap/Secret, Deployment, Service, Ingress, HPA, PodDisruptionBudget, a
default-deny NetworkPolicy, and a migration Job, with dev/staging/prod
overlays patching replicas, resources, and image tags per environment. The
Deployment ships with startup/readiness/liveness probes, a hardened security
context, and automountServiceAccountToken: false.
# 1. Build and push your image, then pin its tag in the overlay:
cd k8s/overlays/prod && kustomize edit set image \
your-registry/fastapi-large-app-template=<registry>/<image>:<tag> && cd -
# 2. Fill in k8s/base/app/secret.yaml (JWT_SECRET_KEY, DB/Redis passwords) and
# review k8s/base/app/configmap.yaml (ALLOWED_HOSTS, CORS_ORIGINS, OTEL endpoint).
# 3. Preview, then deploy (migration Job + all app resources):
kubectl kustomize k8s/overlays/prod
kubectl apply -k k8s/overlays/prodSee k8s/README.md for the full walkthrough.
This 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.
The same checks run in CI (.github/workflows/ci.yml)
on every push and PR: ruff, mypy, an Alembic drift check, the full test suite
with a coverage gate (β₯80%) across Python 3.11β3.13, and a Docker image build.
Locally, make ci runs the identical pipeline.
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.