Production & Scaling

The app is stateless; the metadata Postgres is the only stateful component and the only thing you back up. Everything below follows from that: scale the app horizontally, make the database HA, and treat ENCRYPTION_KEY/JWT_SECRET as recovery-critical secrets.

Secrets management

Never bake secrets into the image or commit a populated .env. Use the platform-native store:

PlatformSecret storeWiring
Kubernetes (any)Sealed Secrets, External Secrets Operator, VaultReference via secrets.existingSecret in Helm values
AWS ECSSecrets Manager / SSM Parameter Storesecrets block in task definition
Azure Container AppsBuilt-in secret store, Key Vault referencesMount as env vars
GCP Cloud RunSecret Manager--update-secrets on deploy
Bare DockerDocker secrets, HashiCorp Vault, sops-encrypted .envMount the file and source it

Horizontal scaling

The application is stateless, sessions live in JWTs, no in-memory caches that need affinity. Scale horizontally by increasing replica count.

ComponentScaling
App pods/tasksStateless, scale up/down freely. Migrations should run as a separate one-shot, not on every pod boot, to avoid races.
Postgres metadata DBVertical scaling on a managed service is the easy path. Read replicas help only at significant scale (1000s of concurrent users), most installations don't need them.
Connection pool (per pod)20 connections by default. With N pods, total connections to Postgres = N × 20. Raise Postgres max_connections or front it with PgBouncer if you exceed the database limit.

Resource sizing

Sensible defaults for a typical install:

ScaleApp CPU / memPostgresReplicas
1-20 users0.5 vCPU / 1 GBdb.t3.small (or 2 vCPU / 4 GB)1
20-100 users1 vCPU / 2 GBdb.t3.medium2
100-500 users2 vCPU / 4 GBdb.m5.large + read replica3-5 with HPA
500+ users4 vCPU / 8 GBdb.m5.xlarge + read replica + PgBouncerHPA on CPU 60%

The "users" figure is concurrent active users. Most installations are far smaller than they expect.

Observability

Backup and restore

Every relevant piece of state is in the db_devops Postgres database. Back that up and you have a restorable system.

Disaster recovery

Standard pattern for HA / DR:

  1. Run app pods/tasks across at least two AZs (Multi-AZ in the orchestrator).
  2. Run Postgres Multi-AZ with synchronous replication (the managed services handle this).
  3. Take regular snapshots of the Postgres volume for point-in-time restore.
  4. Back up ENCRYPTION_KEY and JWT_SECRET to your secret store with versioning enabled.
  5. Document the runbook to recover. Drill it.

Security hardening

Beyond what the in-app docs cover (HTTPS, MFA, RBAC, encryption-at-rest), at the platform level:

Upgrades