Production Readiness Checklist¶
Everything below is documented in its own page already -- this is the one-page index for "am I actually ready to deploy this," pointing at the real docs instead of repeating them. Go through it once before a first production deploy, and again whenever you add something (a queue, a second replica, a new external API) that changes the answer.
Configuration¶
-
APP_ENV=production,APP_DEBUG=false. Debug mode leaks stack traces and internals into error responses -- a browser hitting a broken page gets a full source-level debug page (see API Standards), an API client gets the equivalent in the JSON body. Fine locally, a disclosure bug in production.zeython newscaffolds both as development-friendly defaults; flip them in your deployment's.envor environment variables, not in the repo. -
APP_SECRET_KEYis a real, unique secret, not the valuezeython newgenerated for local dev committed into version control. It signs the session cookie -- see Authentication. -
DATABASE_URLpoints at a real database, not the default SQLite file. SQLite is fine for a single-container demo; anything with more than one app replica needs Postgres/MySQL so writes are visible across processes. See Database & Migrations. - Migrations are applied, not just written --
alembic upgrade head(the generated Docker image'sCMDdoes this for you on a single-container deploy; see Docker). - A risky migration or deploy goes through
zeython down/up, not straight into production traffic against a half-migrated schema -- see Maintenance Mode.
Security¶
- CSRF protection is on -- it is by default for session auth, see CSRF Protection. Don't disable it on a route just because a test was inconvenient.
- Rate limiting is configured on auth endpoints (on by default,
see Rate Limiting) and, if this is a public API,
blanket-enabled across the rest of it too
(
RATE_LIMIT_ENABLED=true). - Security headers are registered --
SecurityHeadersServiceProvideris opt-in, not on by default, because a wrong CSP silently breaks a real app. Decide your policy and register it; see Security Headers. - CORS is scoped to real origins, not
*, ifCorsServiceProvideris registered at all. Wildcard origins on an authenticated API mean any site can read the response. - WebSocket origin checking is on if you're not the only expected client -- see the Origin-check note in WebSockets.
- RBAC/authorization is actually enforced on every route that
needs it -- an undefined ability is a bug, not a silent deny (see
Authorization), so audit routes for a missing
authorize()/Gate.allows()call rather than trusting that one exists. - You've read SECURITY.md -- supported versions and how to report a vulnerability privately, for your own app as much as for the framework.
Database¶
- Connection pooling is sized for your deployment, not left at SQLAlchemy's defaults if you're running multiple app processes against one database -- see Connection pooling.
- A read replica is wired up (
DATABASE_READ_URL+Database.read_replica()) if read load is the bottleneck, not before -- see Read replicas. - N+1 query detection has actually been run against real traffic
paths in dev (
APP_DEBUG=true,N1QueryDetectionServiceProvider) at least once before shipping a new list/index endpoint -- see Detecting N+1s automatically. - Multi-step writes that must succeed or fail together use
transaction()(aSAVEPOINT-scoped nested transaction), not several unguarded writes hoping nothing fails in between -- see Transactions.
Observability¶
- Structured logging is on if you ship to a log aggregator
(Datadog, ELK, CloudWatch Logs Insights, Splunk) --
LOG_FORMAT=json, see Structured (JSON) logging. Plain text is fine if a human is the only consumer. -
X-Request-IDcorrelation is working end to end -- it's on by default (RequestIdServiceProvider), but confirm your proxy/load balancer isn't stripping the header before it reaches the app. See Request/Correlation IDs. - Error monitoring is wired up (Sentry via
ErrorMonitoringServiceProvider+SENTRY_DSN) so an unhandled exception, an exhausted job retry, or a raising scheduled task reaches you instead of only a log line nobody's watching. See Error Monitoring. -
/upis actually wired into your infrastructure's health check -- a load balancer target group, a Kubernetes probe, an uptime monitor -- not just reachable by hand. See Health Check.
Background work¶
-
QUEUE_DRIVER=redis, notmemory, for any job whose loss on a crash or restart you can't tolerate (payment capture, anything with a side effect outside your database) -- see Background Jobs. The in-memory driver is fine for low-stakes work and local dev. - A
queue-workerprocess is actually running if you switched to the Redis driver -- jobs pushed to a durable queue with nothing consuming them just pile up.docker-compose.ymlincludes a commented-out service for this; see Docker. - A scheduler process is running if
schedule.pydefines anything -- a host crontab entry, or the commented-outschedulersidecar indocker-compose.yml. See Scheduling and Docker.
API standards¶
- Response compression is on for a JSON API with non-trivial
payloads (
GzipServiceProvider) -- opt-in, not registered by default. See Compression (gzip). - Conditional GETs are on if clients re-fetch the same resources
often (
ETagServiceProvider) -- know the memory trade-off (it buffers the full response body) before turning it on for large or streamed responses. See Conditional requests (ETags). - Error response shape matches what your clients expect -- the
default
{"error": ..., "status": ...}shape, or RFC 7807application/problem+json(API_PROBLEM_JSON=true) if you're integrating with tooling that expects the standard. Decide once, not per route. See RFC 7807 error responses.
Testing¶
- Tests that touch the database roll back between runs, not leaving state for the next test to trip over -- see Rolling back writes between tests.
- Routes that require login are tested as an authenticated user, not skipped because wiring up a real login flow in a test felt like too much -- see Logging a test client in directly.
- CI is actually green on the branch you're deploying, not "green last time I looked."
What this deliberately doesn't cover¶
This isn't a substitute for your own judgment
This checklist is about configuring and wiring up features the
framework already ships -- it is not a substitute for your own
judgment about your specific deployment: infrastructure choice, TLS
termination, backup strategy, secrets management (a real secrets
manager, not .env in production), and load testing are all yours to
own. If a section above doesn't apply to your app (no background
jobs, no public API), skip it -- this is a checklist to consult, not
a form to fill out completely.