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.localfor local development only.
Required Variables
Supabase (Core)
| Variable | Type | Example | Notes |
|---|---|---|---|
SUPABASE_URL | Public | https://xxxxx.supabase.co | Your Supabase project URL (found in Settings β API) |
SUPABASE_ANON_KEY | Public | eyJhbG... | Anon/public key for client-side operations (safe to expose) |
SUPABASE_SERVICE_ROLE_KEY | Secret | eyJhbG... | Server-only key for privileged operations (keep confidential!) |
NEXT_PUBLIC_SITE_URL | Public | https://pwask.com | Your 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>"
| Variable | Type | Example | Notes |
|---|---|---|---|
SMTP_HOST | Secret | smtp.gmail.com | (SMTP only) Mail server hostname |
SMTP_PORT | Secret | 587 | (SMTP only) 587 (TLS) or 465 (SSL) |
SMTP_USER | Secret | your-email@gmail.com | (SMTP only) Login username |
SMTP_PASS | Secret | xxxxxxxxxxx | (SMTP only) Login password or app token |
EMAIL_FROM | Public | PWASK <no-reply@pwask.com> | Sender email address for all transactional emails |
Analytics & Monitoring (Recommended)
| Variable | Type | Example | Notes |
|---|---|---|---|
NEXT_PUBLIC_SENTRY_DSN | Public | https://xxxxx@sentry.io/xxxxx | Sentry error tracking (optional but recommended) |
NEXT_PUBLIC_GA_MEASUREMENT_ID | Public | G-XXXXXXXXXX | Google Analytics 4 measurement ID |
LOGFLARE_API_KEY | Secret | xxxxx | Logflare for structured logging (optional) |
PWA & Push Notifications (Optional)
| Variable | Type | Example | Notes |
|---|---|---|---|
VAPID_PUBLIC_KEY | Public | BCxxxxx... | Web Push public key (generate with web-push generate-vapid-keys) |
VAPID_PRIVATE_KEY | Secret | xxxxx... | Web Push private key (keep secret!) |
NEXT_PUBLIC_ONE_SIGNAL_APP_ID | Public | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | OneSignal for push notifications |
Image & CDN (Optional)
| Variable | Type | Example | Notes |
|---|---|---|---|
NEXT_PUBLIC_IMAGE_DOMAINS | Public | cdn.example.com,images.example.com | Allowed hostnames for external images (comma-separated) |
CDN_BASE_URL | Public | https://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)
- Connect your GitHub repo to Vercel
- Go to Settings β Environment Variables
- Add all production variables for the
Productionenvironment - Add preview/dev variables for
Previewenvironment - Vercel automatically sets
VERCEL_URLfor preview deployments
Vercel-specific tip: Use NEXT_PUBLIC_SITE_URL=${{ secrets.PRODUCTION_SITE_URL }} in build settings for consistent canonical URLs.
Netlify
- Connect your GitHub repo in Netlify
- Go to Site Settings β Build & Deploy β Environment
- Add variables to
Build environment variablessection - Use
netlify.tomlfor 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
- Connect your GitHub repo to Cloudflare
- Set Framework preset to
Next.js - Add environment variables in Settings β Environment variables
- 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:
- Redeploy your app (rebuild is required)
- 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
Previewscope - 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:
- Generate new key in Supabase/provider
- Add both old and new keys temporarily
- Update all apps to use new key
- Revoke old key after 24 hours
- 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
- Back to Architecture Overview
- FAQ β Common questions about environment setup and troubleshooting