Environment Variables & Production Configuration

This page documents all environment variables needed for PWASK, with examples, security best practices, and platform-specific deployment instructions.

πŸ”’ Security: Store all secrets in your hosting provider's secret managerβ€”never commit them to version control. Use .env.local for local development only.

Required Variables

Supabase (Core)

VariableTypeExampleNotes
SUPABASE_URLPublichttps://xxxxx.supabase.coYour Supabase project URL (found in Settings β†’ API)
SUPABASE_ANON_KEYPubliceyJhbG...Anon/public key for client-side operations (safe to expose)
SUPABASE_SERVICE_ROLE_KEYSecreteyJhbG...Server-only key for privileged operations (keep confidential!)
NEXT_PUBLIC_SITE_URLPublichttps://pwask.comYour production domain (used for links, redirects, canonical tags)

Email & Transactional

Choose one of:

Option A: SMTP (Gmail, custom mail server)

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=app-password-here
EMAIL_FROM="PWASK Support <no-reply@pwask.com>"

Option B: SendGrid API

SENDGRID_API_KEY=SG.xxxxx
EMAIL_FROM="PWASK <noreply@pwask.com>"

Option C: Postmark

POSTMARK_API_TOKEN=xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
EMAIL_FROM="PWASK <hello@pwask.com>"
VariableTypeExampleNotes
SMTP_HOSTSecretsmtp.gmail.com(SMTP only) Mail server hostname
SMTP_PORTSecret587(SMTP only) 587 (TLS) or 465 (SSL)
SMTP_USERSecretyour-email@gmail.com(SMTP only) Login username
SMTP_PASSSecretxxxxxxxxxxx(SMTP only) Login password or app token
EMAIL_FROMPublicPWASK <no-reply@pwask.com>Sender email address for all transactional emails

Analytics & Monitoring (Recommended)

VariableTypeExampleNotes
NEXT_PUBLIC_SENTRY_DSNPublichttps://xxxxx@sentry.io/xxxxxSentry error tracking (optional but recommended)
NEXT_PUBLIC_GA_MEASUREMENT_IDPublicG-XXXXXXXXXXGoogle Analytics 4 measurement ID
LOGFLARE_API_KEYSecretxxxxxLogflare for structured logging (optional)

PWA & Push Notifications (Optional)

VariableTypeExampleNotes
VAPID_PUBLIC_KEYPublicBCxxxxx...Web Push public key (generate with web-push generate-vapid-keys)
VAPID_PRIVATE_KEYSecretxxxxx...Web Push private key (keep secret!)
NEXT_PUBLIC_ONE_SIGNAL_APP_IDPublicxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxOneSignal for push notifications

Image & CDN (Optional)

VariableTypeExampleNotes
NEXT_PUBLIC_IMAGE_DOMAINSPubliccdn.example.com,images.example.comAllowed hostnames for external images (comma-separated)
CDN_BASE_URLPublichttps://cdn.example.com/CDN URL for Supabase Storage files (optional optimization)

Variable Types Explained

  • Public (NEXT_PUBLIC_*): Embedded in client bundle; safe for public keys, IDs
  • Secret: Server-only; never expose in client code
  • Recommended: Nice-to-have for production features (analytics, monitoring)

Platform-Specific Setup Guides

Vercel (Recommended for Next.js)

  1. Connect your GitHub repo to Vercel
  2. Go to Settings β†’ Environment Variables
  3. Add all production variables for the Production environment
  4. Add preview/dev variables for Preview environment
  5. Vercel automatically sets VERCEL_URL for preview deployments

Vercel-specific tip: Use NEXT_PUBLIC_SITE_URL=${{ secrets.PRODUCTION_SITE_URL }} in build settings for consistent canonical URLs.

Netlify

  1. Connect your GitHub repo in Netlify
  2. Go to Site Settings β†’ Build & Deploy β†’ Environment
  3. Add variables to Build environment variables section
  4. Use netlify.toml for build configuration:
[build]
  command = "pnpm build"
  publish = ".next"
  functions = "functions"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

Netlify-specific tip: Netlify has different build commands; ensure you configure pnpm in your build image settings.

Cloudflare Pages

  1. Connect your GitHub repo to Cloudflare
  2. Set Framework preset to Next.js
  3. Add environment variables in Settings β†’ Environment variables
  4. Cloudflare automatically optimizes Next.js deployments

Cloudflare-specific tip: Use Wrangler CLI for local testing: wrangler pages dev -- pnpm dev

Self-Hosted (Docker/Node.js)

Create a Dockerfile:

FROM node:20-alpine
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install
COPY . .
RUN pnpm build
EXPOSE 3000
CMD ["pnpm", "start"]

Build and deploy:

docker build -t pwask:latest .
docker run -e SUPABASE_URL=xxx -e SUPABASE_ANON_KEY=xxx -p 3000:3000 pwask:latest

Self-hosted tip: Use a process manager like PM2 or systemd for automatic restarts.

Runtime vs Build-Time Variables

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ NEXT_PUBLIC_* variables             β”‚
β”‚ - Embedded during build              β”‚
β”‚ - Accessible in client code         β”‚
β”‚ - Example: NEXT_PUBLIC_SENTRY_DSN  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            ↓
       [Build Step]
            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Non-public variables                β”‚
β”‚ - Injected at runtime (server)      β”‚
β”‚ - Accessible only in API routes     β”‚
β”‚ - Example: SUPABASE_SERVICE_ROLE_KEY β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Important: If you add a new NEXT_PUBLIC_* variable:

  1. Redeploy your app (rebuild is required)
  2. Do NOT add it at runtime onlyβ€”it won't be available

Secrets Management Best Practices

Development

Create .env.local (never commit):

SUPABASE_URL=https://your-dev-project.supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Staging/Preview

Use your hosting provider's secret manager:

  • Vercel: Environment Variables with Preview scope
  • Netlify: Deploy context with branch-specific overrides
  • Both support automatic preview per PR

Production

  • Use separate secrets from staging
  • Rotate keys quarterly
  • Use a secrets management tool (HashiCorp Vault, AWS Secrets Manager)
  • Audit who has access to production secrets

Rotation & Security

When rotating keys:

  1. Generate new key in Supabase/provider
  2. Add both old and new keys temporarily
  3. Update all apps to use new key
  4. Revoke old key after 24 hours
  5. Monitor for any auth failures

Environment Variable Validation

Add this to your src/lib/env.ts:

function getEnv(key: string): string {
  const value = process.env[key];
  if (!value) {
    throw new Error(`Missing required environment variable: ${key}`);
  }
  return value;
}

// Use in server code:
const supabaseUrl = getEnv('SUPABASE_URL');

Run validation on startup to catch missing variables early!

Where to Go Next