Before you put a FastAPI service in front of users, work through this list. Some items are framework-specific; most apply to any Python web service.
Configuration
-
pydantic-settingswith env validation at startup. - Secrets via secret manager (Vault / AWS SM / GCP SM) — never in code/image.
- Per-environment config (dev/staging/prod) wired and tested.
-
SECRET_KEYand JWT signing keys rotated procedure documented.
Dependencies
-
uv.lockcommitted; CI usesuv sync --frozen. - Dependabot / Renovate enabled.
- Security scan in CI (pip-audit, trivy, grype).
- Pinned base image digest in Dockerfile.
App structure
-
lifespanfor engines, pools, HTTP clients. - DB session is per-request via
Depends. -
expire_on_commit=Falseon AsyncSessionLocal. -
response_modelset on every public endpoint. -
include_in_schema=Falsefor internal health/metrics endpoints. - All blocking calls audited (no
time.sleep,requests, sync DB in async paths).
Error handling
- Custom exception handlers for
RequestValidationError, app errors. - Don’t leak stack traces in production responses.
- Sentry / equivalent error tracker wired with environment + release tags.
Auth
- Argon2 (or bcrypt) password hashing.
- JWT verification pins
algorithms=[...]explicitly. - Refresh tokens stored hashed; revocable.
- Rate-limit
/tokenand password-reset endpoints. - Generic ‘invalid credentials’ error (no enumeration).
- CORS allow-list pinned to actual frontends.
- HTTPS-only cookies (
Secure,HttpOnly,SameSite=Lax|Strict).
Database
- Pool sized for
workers × replicas × (pool_size + max_overflow) ≤ db_max_connections(or use PgBouncer). -
pool_pre_ping=True,pool_recycle=3600. - All migrations applied via Alembic (no
Base.metadata.create_allin prod). - Migration runs as K8s Job before app rollout.
- Backups + point-in-time recovery configured AND tested.
- Read replicas used for read-heavy paths if needed.
Performance
- No N+1:
selectinload/joinedloadaudited. - Cursor pagination, not offset, for large datasets.
- Slow query log + alerts.
- Background tasks for anything > ~100ms that doesn’t need to block the request.
- CDN cache headers for cacheable responses.
Observability
- Structured JSON logs to stdout.
- Request ID + user/tenant ID in every log line (via contextvars).
- OTEL tracing wired (FastAPI + httpx + DB).
- Trace ID in log lines (correlation).
- Prometheus metrics endpoint exposed.
- Dashboards: request rate, error rate, p50/p95/p99 latency, DB pool, queue depth.
- SLOs defined; burn-rate alerts wired.
Security
- HSTS header.
- CSP if serving HTML.
-
X-Content-Type-Options: nosniff,X-Frame-Options: DENY. - CORS configured deliberately.
- Input validation strict; no SQL string concatenation.
- File uploads: size limited; type checked; stored outside web root.
- Dependencies SBOM generated; signed images (cosign).
Deployment
- Multi-stage Dockerfile; non-root user; distroless or slim runtime.
- K8s Deployment with
>= 2 replicas. -
startupProbe,readinessProbe,livenessProbeall wired. -
terminationGracePeriodSeconds+ preStop sleep. - HPA configured (CPU or custom metric).
- PodDisruptionBudget set.
- Resource requests + memory limits.
- Deploy strategy chosen (rolling default; canary for risky changes).
Capacity / load
- Load tested to expected peak × 2.
- Capacity ceiling per replica known.
- Cost per request roughly known.
Operational readiness
- Runbook for top alerts.
- On-call rotation set up.
- Pager / Slack alerts tested end-to-end.
- Rollback procedure tested (Helm rollback, image tag revert).
- Postmortem template ready.
Documentation
- OpenAPI spec published.
- Auth flow documented for integrators.
- Architecture diagram in repo.
- CONTRIBUTING.md / dev-setup.md current.
Day-one launch
- Soft launch behind feature flag for a cohort.
- Monitor SLOs for 24h.
- Rollout to 100% once SLOs stable.
Read this next
If you want my full FastAPI production starter (lifespan, observability, auth, migrations, Helm), it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .