Skip to content

Environment Variables

Flowstate uses environment variables for all configuration. This document lists every variable used across the platform, organized by service.

Development: Secrets are injected via your team’s secrets management solution and never written to disk. A template file maps environment variable names to secret references that are resolved at runtime.

Production: Secrets are stored in your deployment platform’s secret management system (Docker secrets, Kubernetes secrets, AWS Secrets Manager, etc.).

CRITICAL: Never commit actual secret values to the repository. Always use environment variables or secret management tools.

The backend service (REST API + RPC Gateway) requires the following variables:

VariableRequiredDescription
DATABASE_URLYesMongoDB connection string with replica set

Important:

  • Must include replicaSet parameter (Prisma requirement)
  • Use authSource=admin for authentication
  • In production, use a managed MongoDB service (MongoDB Atlas, AWS DocumentDB)
VariableRequiredDescription
REDIS_URLYesRedis connection string
REDIS_PASSWORDNoRedis password (if auth enabled)

Important:

  • Enable password authentication in production
  • Use Redis Sentinel or Cluster for high availability
VariableRequiredDescription
JWT_SECRETYesSecret for signing user session tokens
ADMIN_JWT_SECRETYesSecret for signing admin session tokens
JWT_EXPIRES_INNoJWT expiration time (default: 30d)
AUTH_COOKIE_DOMAINNo*Parent domain for the session cookie (see below)

Important:

  • Secrets must be at least 32 characters
  • Use cryptographically random strings (not passwords)
  • Generate with: openssl rand -hex 32
  • NEVER reuse secrets across environments
Section titled “AUTH_COOKIE_DOMAIN — cross-subdomain sessions”

Leave this unset in development. The flowstate_auth cookie is then host-only, which is correct locally: cookies ignore port, so the web app (localhost:14321) and the developer portal (localhost:14323) already share one session.

Set it in any environment where surfaces live on different subdomains — e.g. AUTH_COOKIE_DOMAIN=.goflowstate.com so app. and developers. share a session. Without it, a signed-in user is bounced to login when they open the developer portal, because a host-only cookie is never sent to a different host.

Scope it as tightly as the deployment allows: every subdomain beneath the value you set receives the session cookie.

VariableRequiredDescription
CORS_ORIGINYesAllowed frontend origins (comma-separated)

Important:

  • NEVER use * in production (security risk)
  • Include all frontend domains (web, admin)
  • No trailing slashes
VariableRequiredDescription
AGORA_APP_IDYesAgora.io App ID
AGORA_APP_CERTIFICATEYesAgora.io App Certificate

Important:

  • Obtain from Agora Console
  • Keep certificate secret (used for token generation)
VariableRequiredDescription
OPENAI_API_KEYYesOpenAI API key for AI features

Important:

  • Obtain from OpenAI Platform
  • Monitor usage to avoid unexpected costs
  • Set spending limits in OpenAI dashboard
VariableRequiredDescription
APP_URLYesMain application URL (for magic links)
ADMIN_URLYesAdmin dashboard URL

Important:

  • No trailing slashes
  • Must match actual deployment URLs (used in emails)
VariableRequiredDescription
S3_ENDPOINTYesS3-compatible endpoint URL
S3_BUCKETYesBucket name for uploads
S3_ACCESS_KEYYesS3 access key ID
S3_SECRET_KEYYesS3 secret access key
S3_REGIONYesS3 region
S3_PUBLIC_URLYesPublic URL for serving files
S3_FORCE_PATH_STYLENoUse path-style URLs (MinIO)

Supported providers:

  • AWS S3s3.amazonaws.com
  • DigitalOcean Spaces<region>.digitaloceanspaces.com
  • Cloudflare R2<account-id>.r2.cloudflarestorage.com
  • MinIO — Self-hosted (development)

Important:

  • Set S3_FORCE_PATH_STYLE=true for MinIO
  • Configure bucket CORS for direct uploads
  • Enable public read access for uploaded files
VariableRequiredDescription
RATE_LIMIT_WINDOW_MSNoRate limit window in milliseconds (default: 60000)
RATE_LIMIT_MAX_REQUESTSNoMax requests per window (default: 100)

Important:

  • Adjust based on expected traffic
  • Lower limits for auth endpoints (prevent brute force)
  • Higher limits for authenticated users
VariableRequiredDescription
SENDGRID_API_KEYYesSendGrid API key for sending emails
SENDGRID_FROM_EMAILYesSender email address
SENDGRID_FROM_NAMENoSender name (default: Flowstate)

Important:

  • Verify sender domain in SendGrid
  • Monitor email deliverability
  • Set up SPF/DKIM records
VariableRequiredDescription
LOG_LEVELNoLogging level (default: info)
LOG_FORMATNoLog format (default: json)

Important:

  • Use json in production (for log aggregation)
  • Use pretty in development (human-readable)
  • Set to debug for troubleshooting
VariableRequiredDescription
PORTNoBackend REST API port (default: 3000)
GATEWAY_PORTNoRPC Gateway port (default: 3001)
NODE_ENVNoNode.js environment (default: development)

The web application (Astro) requires:

VariableRequiredDescription
SERVER_API_URLYesBackend API URL (server-side only)
PUBLIC_APP_URLNoPublic app URL (client-side)

Important:

  • SERVER_API_URL is used by the Astro proxy (never exposed to browser)
  • Use Docker service names in containers (e.g., http://backend:3000)

The admin dashboard (Astro) requires:

VariableRequiredDescription
SERVER_API_URLYesBackend API URL (server-side only)
OIDC_ISSUER_URLYesOIDC provider issuer URL
OIDC_CLIENT_IDYesOIDC client ID
OIDC_CLIENT_SECRETYesOIDC client secret
OIDC_REDIRECT_URIYesOIDC redirect URI
SUPER_ADMIN_EMAILSYesComma-separated list of super admin emails

Important:

  • Configure OIDC provider (Google, Okta, Auth0, etc.)
  • Add redirect URI to OIDC provider’s allowed list
  • Super admins have full access (choose carefully)

The Electron desktop app uses:

VariableRequiredDescription
VITE_RPC_URLYesRPC Gateway URL (build-time)
DESKTOP_UPDATE_URLNoAuto-update server URL
DESKTOP_S3_BUCKETNoS3 bucket for desktop builds

Important:

  • VITE_RPC_URL is baked into the build (not runtime)
  • Auto-update requires S3 bucket with public read access

These variables are only used in development:

VariableRequiredDescription
SKIP_AUTHNoSkip authentication (dev only)
SEED_DATANoSeed demo data on startup
ENABLE_PLAYGROUNDNoEnable GraphQL playground

CRITICAL: Never set these in production.

Set the following variables for a local development environment. Obtain actual values from your administrator or secrets vault:

# Database
DATABASE_URL=<VALUE>
# Redis
REDIS_URL=<VALUE>
# Authentication
JWT_SECRET=<VALUE>
ADMIN_JWT_SECRET=<VALUE>
# CORS (use your local web app URLs)
CORS_ORIGIN=<VALUE>
# Agora
AGORA_APP_ID=<VALUE>
AGORA_APP_CERTIFICATE=<VALUE>
# OpenAI
OPENAI_API_KEY=<VALUE>
# URLs (use your local service URLs)
APP_URL=<VALUE>
ADMIN_URL=<VALUE>
# Storage
S3_ENDPOINT=<VALUE>
S3_BUCKET=<VALUE>
S3_ACCESS_KEY=<VALUE>
S3_SECRET_KEY=<VALUE>
S3_REGION=<VALUE>
S3_PUBLIC_URL=<VALUE>
S3_FORCE_PATH_STYLE=true
# Email
SENDGRID_API_KEY=<VALUE>
SENDGRID_FROM_EMAIL=<VALUE>
# Logging
LOG_LEVEL=debug
LOG_FORMAT=pretty
# Development flags
SKIP_AUTH=false
SEED_DATA=true
# Database (use your managed MongoDB connection string)
DATABASE_URL=<VALUE>
# Redis (use your managed Redis connection string)
REDIS_URL=<VALUE>
REDIS_PASSWORD=<VALUE>
# Authentication (generate with: openssl rand -hex 32)
JWT_SECRET=<VALUE>
ADMIN_JWT_SECRET=<VALUE>
JWT_EXPIRES_IN=30d
# CORS (list your actual production domains)
CORS_ORIGIN=<VALUE>
# Agora
AGORA_APP_ID=<VALUE>
AGORA_APP_CERTIFICATE=<VALUE>
# OpenAI
OPENAI_API_KEY=<VALUE>
# URLs
APP_URL=<VALUE>
ADMIN_URL=<VALUE>
# Storage (AWS S3 or compatible)
S3_ENDPOINT=<VALUE>
S3_BUCKET=<VALUE>
S3_ACCESS_KEY=<VALUE>
S3_SECRET_KEY=<VALUE>
S3_REGION=<VALUE>
S3_PUBLIC_URL=<VALUE>
# Rate Limiting
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=100
# Email
SENDGRID_API_KEY=<VALUE>
SENDGRID_FROM_EMAIL=<VALUE>
SENDGRID_FROM_NAME=Flowstate
# Logging
LOG_LEVEL=info
LOG_FORMAT=json
# Server
PORT=3000
GATEWAY_PORT=3001
NODE_ENV=production
# Backend API
SERVER_API_URL=<VALUE>
# OIDC provider (Google, Okta, Auth0, etc.)
OIDC_ISSUER_URL=<VALUE>
OIDC_CLIENT_ID=<VALUE>
OIDC_CLIENT_SECRET=<VALUE>
OIDC_REDIRECT_URI=<VALUE>
# Super Admins
SUPER_ADMIN_EMAILS=<VALUE>

The backend validates all required environment variables on startup. If any are missing or invalid, the server will not start.

Validation checks:

  • Required variables are present
  • URLs are valid (no trailing slashes)
  • JWT secrets are at least 32 characters
  • Database URL includes replica set
  • CORS origins are not * in production

Example error:

Error: Missing required environment variable: JWT_SECRET
Error: CORS_ORIGIN cannot be '*' in production
Error: JWT_SECRET must be at least 32 characters
  1. Never commit secrets — Use .env files (gitignored) or secret management tools
  2. Rotate secrets regularly — Change JWT secrets, API keys every 90 days
  3. Use strong secrets — Generate with openssl rand -hex 32
  4. Restrict CORS — Never use * in production
  5. Enable authentication — Set Redis password, MongoDB auth
  6. Monitor access — Log all secret access in your vault system
  7. Separate environments — Different secrets for dev/staging/production
  8. Limit permissions — Use least-privilege IAM roles for S3, database
  9. Encrypt at rest — Enable encryption for database, Redis, S3
  10. Audit regularly — Review who has access to secrets
Error: Missing required environment variable: DATABASE_URL

Solution: Add the variable to your .env file or deployment configuration.

Error: DATABASE_URL must include replicaSet parameter

Solution: Add ?replicaSet=rs0 to your MongoDB connection string.

Access to fetch at 'https://api.your-domain.com' from origin 'https://app.your-domain.com' has been blocked by CORS policy

Solution: Add https://app.your-domain.com to CORS_ORIGIN.

Error: JWT_SECRET must be at least 32 characters

Solution: Generate a new secret: openssl rand -hex 32

Error: Could not connect to S3 endpoint

Solution: Verify S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY are correct. For MinIO, ensure S3_FORCE_PATH_STYLE=true.

Error: Redis connection refused

Solution: Verify REDIS_URL is correct and Redis is running. Check firewall rules.

For more details on specific services: