Environment Variables

Environment Variables — Master Reference

Every environment variable used across all services, its purpose, and where it should be stored.


Variable Reference

VariableService(s)Secret?Storage Location
DATABASE_URLweb-app, api, workerYesGCP Secret Manager (Neon connection string)
BETTER_AUTH_SECRETweb-appYesGCP Secret Manager
BETTER_AUTH_JWKS_URLapi, workerNoCloud Run env / GitHub Actions variable
VITE_API_URLweb-appNoDocker build arg (inlined at build time)
NEXT_PUBLIC_API_URLmarketingNoDocker build arg (inlined at build time)
EXPO_PUBLIC_API_URLiosNoBuild-time public config
GCP_PROJECT_IDapi, worker, infraNoGitHub Actions variable
BIGQUERY_DATASETworkerNoGitHub Actions variable
WELLSKY_CLIENT_IDworkerYesGCP Secret Manager
WELLSKY_CLIENT_SECRETworkerYesGCP Secret Manager
OTEL_EXPORTER_OTLP_ENDPOINTapi, workerNoGitHub Actions variable / Cloud Run env
RESTATE_* (runtime endpoint + identity/signing keys)workerYesGCP Secret Manager

Auth is Better Auth on the applications-UI server (the Vite + TanStack ui/web-app), storing its tables in Neon. The app server needs DATABASE_URL + BETTER_AUTH_SECRET; the FastAPI backend validates the issued JWTs via BETTER_AUTH_JWKS_URL. There are no Supabase Auth keys. See Frontend and Backend.

Durable-execution engine: Restate Cloud (managed). The Restate Cloud environment endpoint plus its request-signing / identity keys (RESTATE_*) live in GCP Secret Manager. PHI never travels as plaintext through Restate Cloud — it is encrypted at the serde boundary inside the handler (GCP-KMS-backed encrypting Serde), so the journal and virtual-object state hold ciphertext only (an encrypted conduit, no BAA required). Never commit secrets. See Backend.


PR Environment Secrets

Additional secrets required for ephemeral PR preview environments:

VariableSecret?Storage Location
GCP_PROJECT_IDNoGitHub Actions variable
GCP_REGIONNoGitHub Actions variable
NEON_API_KEYYesGitHub Actions secret
NEON_PROJECT_IDNoGitHub Actions variable

GCP authentication uses Workload Identity Federation — no GCP_CREDENTIALS JSON key secret is needed. The per-PR Neon branch DATABASE_URL and branch-scoped Better Auth config are minted in CI and destroyed with the branch. See PR Preview Environments.


Storage Locations

Cloud Run Environment Variables

Used for the web-app, marketing, api, and worker service configuration. Non-secret values are set directly as Cloud Run env vars; secrets are stored in GCP Secret Manager and mounted at deploy time. Note: VITE_* / NEXT_PUBLIC_* / EXPO_PUBLIC_* variables used in client-side code are inlined at build time and must be passed as Docker build arguments — they cannot be changed via runtime Cloud Run env vars.

Pulumi ESC + GCP Secret Manager

Pulumi ESC is the declarative source of truth for every environment's config + secrets; it materializes them into GCP Secret Manager, the IAM-scoped runtime store (inside the Google BAA). Cloud Run mounts secrets from Secret Manager at deploy time. There is no database-resident vault — Neon does not support supabase_vault / pgsodium, and a DB-resident secret would be copied into every preview branch. See Secret Management.

GitHub Actions Variables / Secrets

  • Variables (non-secret): Used in CI/CD workflows for configuration like project IDs, regions, and dataset names.
  • Secrets: Used for deployment credentials (NEON_API_KEY) and service connection strings minted per-PR.

.env.example Files

Each service must have a .env.example file listing all required variables with placeholder values:

LocationVariables
ui/web-app/.env.exampleDATABASE_URL, BETTER_AUTH_SECRET, VITE_API_URL
ui/marketing/.env.exampleNEXT_PUBLIC_API_URL
backend/api/.env.exampleDATABASE_URL, BETTER_AUTH_JWKS_URL
backend/worker/.env.exampleDATABASE_URL, BETTER_AUTH_JWKS_URL, BIGQUERY_DATASET, WELLSKY_CLIENT_ID, WELLSKY_CLIENT_SECRET, OTEL_EXPORTER_OTLP_ENDPOINT, RESTATE_* (runtime endpoint + identity keys)
Root .env.exampleDev-time defaults for process-compose

Security Rules

  1. Never commit secrets to the repository. Use .gitignore to exclude .env files.
  2. Never log secret values. The pydantic-settings BaseSettings class prevents accidental logging. Never log DATABASE_URL.
  3. Use the VITE_ / NEXT_PUBLIC_ / EXPO_PUBLIC_ prefixes only for values safe to expose in client-side JavaScript.
  4. Rotate secrets regularly and audit access logs. Add a new Secret Manager version, then destroy the old one after cutover.

See HIPAA Compliance for additional security requirements.