Files
thrilltrack-explorer/migration/ENVIRONMENT_VARIABLES.md

6.8 KiB

Environment Variables Guide

For: ThrillWiki Next.js 15 Migration
Last Updated: November 9, 2025


🎯 Overview

This guide covers all environment variables required for the ThrillWiki migration from React→Next.js 15 and Supabase→Django.

🔑 Critical Rules

  1. NO HARDCODED VALUES - All configuration must use environment variables
  2. Client vs Server - Understand NEXT_PUBLIC_ prefix usage
  3. Never commit secrets - .env.local in .gitignore
  4. .env.example - Document all required vars (without values)
  5. Validate on startup - Fail fast if required vars missing

📋 Required Environment Variables

Next.js Client-Side (Public)

These variables are exposed to the browser. Use NEXT_PUBLIC_ prefix.

# Django API (required)
NEXT_PUBLIC_DJANGO_API_URL=https://api.thrillwiki.com

# CloudFlare Images (required for uploads)
NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID=your_account_id_here

Next.js Server-Side (Private)

These variables are ONLY available server-side. NO NEXT_PUBLIC_ prefix.

# CloudFlare API Token (for image uploads from server)
CLOUDFLARE_API_TOKEN=your_secret_token_here

# Django Admin Credentials (if needed for server-side operations)
DJANGO_ADMIN_KEY=your_admin_key_here

Legacy Supabase (Temporary - Remove in Phase 14)

Keep these ONLY during migration phases 1-13:

# Supabase (to be removed)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key_here

📁 File Structure

project-root/
├── .env.local          # Local development (git-ignored)
├── .env.example        # Template (git-committed)
├── .env.production     # Production (if needed, git-ignored)
└── .env.test           # Testing (git-ignored)

.env.local (Development)

# ================================
# Next.js Environment Variables
# ================================

# Django REST API
NEXT_PUBLIC_DJANGO_API_URL=http://localhost:8000/api/v1

# CloudFlare Images
NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID=your_dev_account_id
CLOUDFLARE_API_TOKEN=your_dev_token

# Supabase (temporary - remove after Phase 14)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key

# Development flags
NODE_ENV=development

.env.example (Template)

# ================================
# Next.js Environment Variables
# Copy to .env.local and fill in values
# ================================

# Django REST API (required)
NEXT_PUBLIC_DJANGO_API_URL=

# CloudFlare Images (required)
NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_API_TOKEN=

# Supabase (temporary - will be removed)
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=

.env.production (Production)

# Django REST API
NEXT_PUBLIC_DJANGO_API_URL=https://api.thrillwiki.com

# CloudFlare Images
NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID=production_account_id
CLOUDFLARE_API_TOKEN=production_secret_token

# Production settings
NODE_ENV=production

🔐 Security Best Practices

1. Client vs Server Variables

// ❌ WRONG - Exposes secret to browser
const apiKey = process.env.CLOUDFLARE_API_TOKEN;

// ✅ CORRECT - Only available server-side
// In Server Component or API Route
const apiKey = process.env.CLOUDFLARE_API_TOKEN;

// ✅ CORRECT - Public variable in client
const apiUrl = process.env.NEXT_PUBLIC_DJANGO_API_URL;

2. Never Log Secrets

// ❌ WRONG
console.log('API Token:', process.env.CLOUDFLARE_API_TOKEN);

// ✅ CORRECT
console.log('API URL:', process.env.NEXT_PUBLIC_DJANGO_API_URL);

3. Validate Environment Variables

// lib/env.ts
import { z } from 'zod';

const envSchema = z.object({
  NEXT_PUBLIC_DJANGO_API_URL: z.string().url(),
  NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID: z.string().min(1),
  CLOUDFLARE_API_TOKEN: z.string().min(1).optional(), // Server-only
});

// Validate on app start
export const env = envSchema.parse({
  NEXT_PUBLIC_DJANGO_API_URL: process.env.NEXT_PUBLIC_DJANGO_API_URL,
  NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID: process.env.NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID,
  CLOUDFLARE_API_TOKEN: process.env.CLOUDFLARE_API_TOKEN,
});

// Usage
import { env } from '@/lib/env';
const apiUrl = env.NEXT_PUBLIC_DJANGO_API_URL;

🚀 Deployment Environments

Vercel

Set environment variables in Vercel dashboard:

  1. Go to Project Settings → Environment Variables
  2. Add each variable:
    • NEXT_PUBLIC_DJANGO_API_URL = https://api.thrillwiki.com
    • NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID = your_account
    • CLOUDFLARE_API_TOKEN = your_token (mark as secret)

Docker

Pass via docker-compose.yml:

services:
  nextjs:
    environment:
      - NEXT_PUBLIC_DJANGO_API_URL=https://api.thrillwiki.com
      - NEXT_PUBLIC_CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID}
      - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}

🧪 Testing

Check Variables Are Loaded

// Test in dev console (browser)
console.log('API URL:', process.env.NEXT_PUBLIC_DJANGO_API_URL);
// Should show the URL

console.log('Secret Token:', process.env.CLOUDFLARE_API_TOKEN);
// Should show 'undefined' (not exposed to client)

Verify Build-Time Variables

# Build with verbose output
bun run build

# Check if variables are embedded
grep -r "NEXT_PUBLIC_DJANGO_API_URL" .next/

📊 Migration Phases

Phase 1-13: Dual Variables

# Keep both during migration
NEXT_PUBLIC_DJANGO_API_URL=...
NEXT_PUBLIC_SUPABASE_URL=...

Phase 14: Remove Supabase

# Remove these completely
# NEXT_PUBLIC_SUPABASE_URL=...
# NEXT_PUBLIC_SUPABASE_ANON_KEY=...

# Keep only Django
NEXT_PUBLIC_DJANGO_API_URL=...

⚠️ Common Issues

Issue: Variable is undefined in browser

Cause: Missing NEXT_PUBLIC_ prefix

Fix: Rename variable:

# Wrong
DJANGO_API_URL=https://api.thrillwiki.com

# Right
NEXT_PUBLIC_DJANGO_API_URL=https://api.thrillwiki.com

Issue: Variable not updating after change

Cause: Next.js caches env vars at build time

Fix: Restart dev server:

# Stop server (Ctrl+C)
bun run dev

Issue: Hardcoded URL slipped through

Find: Search codebase:

grep -r "https://api.thrillwiki.com" src/ --exclude-dir=node_modules

Fix: Replace with env var:

// Before
const API_URL = "https://api.thrillwiki.com";

// After
const API_URL = process.env.NEXT_PUBLIC_DJANGO_API_URL;


Document Version: 1.0
Last Updated: November 9, 2025