# Production Environment Variables **Last Updated:** January 2025 **Purpose:** Complete reference for all production environment variables --- ## Quick Reference ### Required Variables (Must Have) | Variable | Description | Example | |----------|-------------|---------| | `NODE_ENV` | Environment mode | `production` | | `NEXT_PUBLIC_APP_URL` | Public application URL | `https://your-domain.com` | | `DATABASE_URL` | Supabase PostgreSQL connection string | `postgresql://postgres:pass@db.xxx.supabase.co:5432/postgres` | | `RUNTIME_DATABASE_URL` | Supabase connection pooling URL | `postgresql://postgres:pass@db.xxx.supabase.co:6543/postgres?pgbouncer=true` | | `NEXT_PUBLIC_SUPABASE_URL` | Supabase project URL | `https://xxx.supabase.co` | | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase anonymous key | `eyJhbGc...` | | `SUPABASE_SERVICE_ROLE_KEY` | Supabase service role key | `eyJhbGc...` | | `ADMIN_PASSWORD` | Admin dashboard password | `StrongPassword123!` | | `SESSION_SECRET` | Session encryption secret (32+ chars) | `openssl rand -base64 32` | | `CSRF_SECRET` | CSRF protection secret | `openssl rand -base64 24` | | `REDIS_URL` | Redis connection string | `redis://localhost:6379` | ### Recommended Variables (Should Have) | Variable | Description | Example | |----------|-------------|---------| | `NEXT_PUBLIC_SENTRY_DSN` | Sentry error tracking | `https://xxx@sentry.io/xxx` | | `RESEND_API_KEY` | Resend email API key | `re_xxx` | | `FROM_EMAIL` | Email sender address | `noreply@your-domain.com` | ### Optional Variables (Nice to Have) | Variable | Description | Example | |----------|-------------|---------| | `SHADOW_DATABASE_URL` | Shadow DB for migrations | `postgresql://...` | | `SUPABASE_URL` | Internal Supabase URL | `http://supabase-kong:8000` | | `SMTP_HOST` | SMTP server (legacy) | `smtp.sendgrid.net` | | `SMTP_PORT` | SMTP port | `587` | | `SMTP_USER` | SMTP username | `apikey` | | `SMTP_PASS` | SMTP password | `SG.xxx` | | `TWILIO_ACCOUNT_SID` | Twilio account SID | `ACxxx` | | `TWILIO_AUTH_TOKEN` | Twilio auth token | `xxx` | | `TWILIO_PHONE_NUMBER` | Twilio phone number | `+1234567890` | | `NEXT_PUBLIC_GA_MEASUREMENT_ID` | Google Analytics ID | `G-XXXXXXXXXX` | | `OPENWEATHER_API_KEY` | OpenWeather API key | `xxx` | | `ENABLE_NOTIFICATIONS` | Enable notifications | `true` | | `ENABLE_ANALYTICS` | Enable analytics | `false` | --- ## Detailed Descriptions ### Environment **`NODE_ENV`** (Required) - **Type:** Enum (`production` | `development` | `test`) - **Value:** `production` - **Description:** Sets the Node.js environment mode - **Note:** Must be exactly `production` for production deployments ### Application URL **`NEXT_PUBLIC_APP_URL`** (Required) - **Type:** URL String - **Format:** `https://your-domain.com` - **Description:** Public URL of your application - **Usage:** Used for absolute URLs, email links, OAuth callbacks, etc. - **Note:** Must use `https://` in production ### Database **`DATABASE_URL`** (Required) - **Type:** Supabase PostgreSQL Connection String - **Format:** `postgresql://postgres:[PASSWORD]@db.[PROJECT_REF].supabase.co:5432/postgres` - **Description:** Direct Supabase PostgreSQL connection (port 5432) - used for migrations - **Get From:** Supabase Dashboard → Settings → Database → Connection String → Direct connection - **Example:** `postgresql://postgres:yourpassword@db.abcdefghijklmnop.supabase.co:5432/postgres` - **Security:** Contains credentials - keep secret - **Note:** Use direct connection (port 5432) for migrations **`RUNTIME_DATABASE_URL`** (Required) - **Type:** Supabase Connection Pooling String - **Format:** `postgresql://postgres:[PASSWORD]@db.[PROJECT_REF].supabase.co:6543/postgres?pgbouncer=true` - **Description:** Supabase connection pooling URL (port 6543) - used for runtime queries - **Get From:** Supabase Dashboard → Settings → Database → Connection String → Connection pooling - **Example:** `postgresql://postgres:yourpassword@db.abcdefghijklmnop.supabase.co:6543/postgres?pgbouncer=true` - **Note:** If not set, falls back to `DATABASE_URL` (not recommended for production) - **Why:** Connection pooling prevents hitting Supabase connection limits **`SHADOW_DATABASE_URL`** (Optional) - **Type:** Supabase PostgreSQL Connection String - **Description:** Shadow database for Prisma migrations (only needed if Supabase requires it) - **When Needed:** Only if Prisma migrations fail without a shadow database - **Note:** Usually same as `DATABASE_URL` for Supabase ### Supabase **`NEXT_PUBLIC_SUPABASE_URL`** (Required) - **Type:** URL String - **Format:** `https://your-project-id.supabase.co` - **Description:** Supabase project URL (public, exposed to browser) - **Security:** Safe to expose - used in client-side code **`NEXT_PUBLIC_SUPABASE_ANON_KEY`** (Required) - **Type:** String - **Description:** Supabase anonymous/public key - **Security:** Safe to expose - used in client-side code - **Note:** Has limited permissions, safe for browser **`SUPABASE_SERVICE_ROLE_KEY`** (Required) - **Type:** String - **Description:** Supabase service role key (server-side only) - **Security:** NEVER expose to client - has admin privileges - **Usage:** Server-side API routes and server components only - **Warning:** Keep this secret - never commit to version control **`SUPABASE_URL`** (Optional) - **Type:** URL String - **Format:** `http://supabase-kong:8000` (internal Docker network) - **Description:** Internal Supabase URL for server-side requests - **When Needed:** When app and Supabase are in same Docker network - **Note:** If not set, falls back to `NEXT_PUBLIC_SUPABASE_URL` ### Authentication & Security **`ADMIN_PASSWORD`** (Required) - **Type:** String - **Min Length:** 8 characters - **Recommended:** 12+ characters with mixed case, numbers, symbols - **Description:** Password for admin dashboard access - **Security:** Must be strong and unique - **Generation:** Use password manager or `openssl rand -base64 16` - **Warning:** Cannot use development default in production **`SESSION_SECRET`** (Required) - **Type:** String - **Min Length:** 32 characters - **Description:** Secret key for session encryption - **Security:** Must be strong random string - **Generation:** `openssl rand -base64 32` - **Warning:** Cannot use development default in production **`CSRF_SECRET`** (Required) - **Type:** String - **Description:** CSRF token secret - **Security:** Required in production for security - **Generation:** `openssl rand -base64 24` - **Note:** Must be different from `SESSION_SECRET` ### Redis **`REDIS_URL`** (Required in Production) - **Type:** Redis Connection String - **Format:** `redis://host:port` or `redis://:password@host:port` - **Description:** Redis connection for rate limiting - **Example:** `redis://localhost:6379` or `redis://:password@redis.example.com:6379` - **Why Required:** Rate limiting requires Redis in production (distributed systems) - **Note:** Falls back to in-memory if not available (not recommended for production) ### Email Service **Option 1: Resend (Recommended)** **`RESEND_API_KEY`** (Optional but Recommended) - **Type:** String - **Format:** `re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` - **Description:** Resend API key for transactional emails - **Get From:** [resend.com/api-keys](https://resend.com/api-keys) **`FROM_EMAIL`** (Optional but Recommended) - **Type:** Email String - **Format:** `noreply@your-domain.com` - **Description:** Email sender address - **Note:** Must be verified in Resend dashboard **Option 2: SMTP (Legacy)** **`SMTP_HOST`** (Optional) - **Type:** String - **Example:** `smtp.sendgrid.net` - **Description:** SMTP server hostname **`SMTP_PORT`** (Optional) - **Type:** Number - **Example:** `587` - **Description:** SMTP server port **`SMTP_USER`** (Optional) - **Type:** String - **Example:** `apikey` - **Description:** SMTP username **`SMTP_PASS`** (Optional) - **Type:** String - **Description:** SMTP password/API key ### SMS Service (Twilio) **`TWILIO_ACCOUNT_SID`** (Optional) - **Type:** String - **Format:** `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` - **Description:** Twilio account SID - **Get From:** [Twilio Console](https://console.twilio.com) **`TWILIO_AUTH_TOKEN`** (Optional) - **Type:** String - **Description:** Twilio authentication token - **Security:** Keep secret - never expose to client **`TWILIO_PHONE_NUMBER`** (Optional) - **Type:** Phone Number String - **Format:** `+1234567890` - **Description:** Twilio phone number for sending SMS ### Feature Flags **`ENABLE_NOTIFICATIONS`** (Optional) - **Type:** Boolean - **Default:** `true` - **Values:** `true` | `false` | `1` | `0` - **Description:** Enable email/SMS notifications **`ENABLE_ANALYTICS`** (Optional) - **Type:** Boolean - **Default:** `false` - **Values:** `true` | `false` | `1` | `0` - **Description:** Enable analytics tracking ### Error Tracking **`NEXT_PUBLIC_SENTRY_DSN`** (Recommended) - **Type:** URL String - **Format:** `https://xxx@sentry.io/xxx` - **Description:** Sentry DSN for error tracking - **Get From:** [Sentry Project Settings](https://sentry.io/settings/projects/) - **Security:** Safe to expose (public DSN) ### Analytics **`NEXT_PUBLIC_GA_MEASUREMENT_ID`** (Optional) - **Type:** String - **Format:** `G-XXXXXXXXXX` - **Description:** Google Analytics Measurement ID - **Get From:** [Google Analytics Admin](https://analytics.google.com) ### Weather API **`OPENWEATHER_API_KEY`** (Optional) - **Type:** String - **Description:** OpenWeather API key - **Get From:** [openweathermap.org/api](https://openweathermap.org/api) ### Ollama AI (Wedding Concierge) **`OLLAMA_URL`** (Optional) - **Type:** URL String - **Description:** Ollama server URL for AI concierge - **Format:** `http://host:port` or `https://host:port` - **Coolify:** Use internal Docker network URL (e.g., `http://ollama-CONTAINER_ID:11434`) or external URL if Ollama is on a different service - **Default:** `http://localhost:11434` - **Security:** Server-side only (not exposed to browser) - **Example:** `http://ollama:11434` (internal Docker network) or `https://ollama.yourdomain.com` (external) **`OLLAMA_MODEL`** (Optional) - **Type:** String - **Description:** Ollama model name to use for concierge - **Default:** `jarvis-concierge` - **Example:** `llama3`, `mistral`, `jarvis-concierge` **`OLLAMA_TEMPERATURE`** (Optional) - **Type:** Number (as string) - **Description:** Temperature for AI responses (0.0-1.0) - **Default:** `0.7` - **Example:** `0.7` (balanced), `0.5` (more focused), `0.9` (more creative) --- ## Security Best Practices 1. **Never Commit Secrets** - `.env.production` is in `.gitignore` - Never commit actual values to version control - Use `.env.production.example` as template 2. **Strong Secrets** - `SESSION_SECRET`: Use `openssl rand -base64 32` - `CSRF_SECRET`: Use `openssl rand -base64 24` - `ADMIN_PASSWORD`: Minimum 12 characters, mix of letters, numbers, symbols 3. **Different Secrets Per Environment** - Use different secrets for dev/staging/prod - Never reuse production secrets in development 4. **Secrets Management** - Use secrets management service (AWS Secrets Manager, HashiCorp Vault) - Rotate secrets regularly - Use environment-specific secrets 5. **Public Variables** - `NEXT_PUBLIC_*` variables are exposed to browser - Never put secrets in `NEXT_PUBLIC_*` variables - Only use for non-sensitive configuration 6. **Database Security** - Use strong, unique database passwords - Use connection pooling in production - Restrict database access by IP when possible --- ## Validation Environment variables are validated on application startup using Zod schemas in `src/lib/env.ts`. **Validation happens:** - On application startup - Type checking - Format validation - Required field checking **Errors:** - Invalid variables cause application to fail on startup - Clear error messages indicate which variables are invalid **Test validation:** ```bash # Type check npm run typecheck # Build (validates environment) npm run build ``` --- ## Generation Commands ```bash # Generate SESSION_SECRET (32+ characters) openssl rand -base64 32 # Generate CSRF_SECRET (24+ characters) openssl rand -base64 24 # Generate ADMIN_PASSWORD (16 characters) openssl rand -base64 16 ``` --- ## Example Production Configuration ```bash # Environment NODE_ENV=production # Application NEXT_PUBLIC_APP_URL=https://themoyos.co.za # Database # Supabase PostgreSQL connection strings # Get from: Supabase Dashboard → Settings → Database → Connection String DATABASE_URL=postgresql://postgres:YourPassword@db.abcdefghijklmnop.supabase.co:5432/postgres RUNTIME_DATABASE_URL=postgresql://postgres:YourPassword@db.abcdefghijklmnop.supabase.co:6543/postgres?pgbouncer=true # Supabase NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # Security ADMIN_PASSWORD=YourStrongAdminPassword123! SESSION_SECRET=f3ERSdncczdgAruOxCKXqqd5O6KIn81VQDlZ0nOARteUQ9nq6YBJi6MqJgzqazVQ CSRF_SECRET=K8mN2pQ5rT9vW1xY4zA7bC0dE3fG6hI9j # Redis REDIS_URL=redis://redis.example.com:6379 # Email (Resend) RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx FROM_EMAIL=noreply@themoyos.co.za # Error Tracking NEXT_PUBLIC_SENTRY_DSN=https://xxx@sentry.io/xxx # Feature Flags ENABLE_NOTIFICATIONS=true ENABLE_ANALYTICS=true ``` --- ## Related Documentation - [SSOT.md - Environment Configuration](SSOT.md#environment-configuration) - Main documentation - [SSOT.md - Deployment (Proxmox)](SSOT.md#deployment-proxmox) - Deployment guide - `.env.production.example` - Template file --- **Last Updated:** January 2025 **Maintained By:** Development Team