Skip to content
Environment Variables logo

Environment Variables

> **Skill Purpose:** Secure environment variable and secrets management patterns

Coverage-Creatives/zeus0installs0stars

SKILL.md

Full skill instructions

Environment Variables

Skill Purpose: Secure environment variable and secrets management patterns


Core Skill Pattern

Objective: Establish secure, validated environment variable management across all project environments.

Universal Pattern:

  1. Define environment variable categories and schema
  2. Create validation patterns for required variables
  3. Establish secure storage and access patterns
  4. Set up environment-specific variable sets
  5. Create secrets management and rotation procedures

Key Decisions (Project-Specific):

  • Variable naming conventions and categories
  • Validation strictness and error handling
  • Secrets storage method (vault, encrypted files, etc.)
  • Environment variable inheritance patterns
  • Team access and rotation policies

Project-Specific Implementation Notes

Customize per project:

  • Variable categories based on application needs
  • Security requirements and compliance standards
  • Team size and access control needs
  • Integration with existing secrets management
  • Development vs production variable differences

Example Implementation (Next.js Environment Variables Pattern)

Note: This is an example pattern. Adapt variable categories and security measures based on your specific project requirements.

Prerequisites (Example)

  • Project initialized
  • Basic security understanding
  • Team access patterns defined

Example: Next.js Environment Variables Implementation

Framework-Specific Example: This demonstrates the pattern using Next.js environment variables. Adapt for your tech stack and security requirements.

1. Create Environment Variable Structure

# Create environment directories
mkdir -p .env.example
mkdir -p .env.local.example
mkdir -p .env.development.example
mkdir -p .env.test.example
mkdir -p .env.production.example

2. Create Base Environment Template

Create .env.example:

# Database Configuration
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=

# Authentication
NEXTAUTH_SECRET=
NEXTAUTH_URL=
NEXTAUTH_TRUST_HOST=

# Application Configuration
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME=Zeus Framework App
NEXT_PUBLIC_APP_VERSION=1.0.0

# API Configuration
API_BASE_URL=http://localhost:3000/api
API_TIMEOUT=30000

# Feature Flags
NEXT_PUBLIC_ENABLE_ANALYTICS=false
NEXT_PUBLIC_ENABLE_DEBUG=false
NEXT_PUBLIC_ENABLE_LOGGING=true

# Third-party Services
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=
NEXT_PUBLIC_SENTRY_DSN=
NEXT_PUBLIC_HOTJAR_ID=

# Email Service
RESEND_API_KEY=
[email protected]

# Payment Processing
STRIPE_PUBLISHABLE_KEY=
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=

# File Storage
NEXT_PUBLIC_STORAGE_URL=
STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=
STORAGE_REGION=
STORAGE_BUCKET=

# Redis Configuration
REDIS_URL=redis://localhost:6379
REDIS_PASSWORD=

# Search Service
NEXT_PUBLIC_ALGOLIA_APP_ID=
ALGOLIA_SEARCH_API_KEY=
ALGOLIA_ADMIN_API_KEY=

# Monitoring
NEXT_PUBLIC_LOGROCKET_APP_ID=
LOGROCKET_URL=

# Development Tools
NEXT_PUBLIC_DEVTOOLS=false
NEXT_PUBLIC_STORYBOOK_ENABLED=false

# Security
CORS_ORIGIN=http://localhost:3000
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW_MS=900000

# Deployment
VERCEL_URL=
VERCEL_PROJECT_ID=
BUILD_ID=

# Testing
TEST_DATABASE_URL=
TEST_SUPABASE_ANON_KEY=

3. Create Environment-Specific Templates

Create .env.development.example:

# Development Environment Variables
# Copy this to .env.development.local

# Database
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_dev_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_dev_service_key

# Authentication
NEXTAUTH_SECRET=your_dev_secret_at_least_32_characters_long
NEXTAUTH_URL=http://localhost:3000

# Application
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME=Zeus Framework (Dev)
NEXT_PUBLIC_ENABLE_DEBUG=true
NEXT_PUBLIC_ENABLE_LOGGING=true

# Development Tools
NEXT_PUBLIC_DEVTOOLS=true
NEXT_PUBLIC_STORYBOOK_ENABLED=true

# Testing
TEST_DATABASE_URL=postgresql://postgres:password@localhost:54322/​test_db

Create .env.test.example:

# Test Environment Variables
# Copy this to .env.test.local

# Database
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54323
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_test_anon_key

# Authentication
NEXTAUTH_SECRET=test_secret_at_least_32_characters_long
NEXTAUTH_URL=http://localhost:3000

# Application
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME=Zeus Framework (Test)
NEXT_PUBLIC_ENABLE_DEBUG=false
NEXT_PUBLIC_ENABLE_LOGGING=false

# Testing
TEST_DATABASE_URL=postgresql://postgres:password@localhost:54324/​test_db

Create .env.production.example:

# Production Environment Variables
# Copy this to .env.production.local

# Database
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_prod_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_prod_service_key

# Authentication
NEXTAUTH_SECRET=your_prod_secret_at_least_32_characters_long
NEXTAUTH_URL=https://your-domain.com

# Application
NEXT_PUBLIC_APP_URL=https://your-domain.com
NEXT_PUBLIC_APP_NAME=Zeus Framework
NEXT_PUBLIC_ENABLE_DEBUG=false
NEXT_PUBLIC_ENABLE_LOGGING=false

# Third-party Services
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=GA_MEASUREMENT_ID
NEXT_PUBLIC_SENTRY_DSN=https://your-sentry-dsn
NEXT_PUBLIC_HOTJAR_ID=your_hotjar_id

# Email
RESEND_API_KEY=re_your_resend_api_key
[email protected]

# Payment
STRIPE_PUBLISHABLE_KEY=pk_live_your_stripe_key
STRIPE_SECRET_KEY=sk_live_your_stripe_secret
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret

# File Storage
NEXT_PUBLIC_STORAGE_URL=https://your-storage.s3.amazonaws.com
STORAGE_ACCESS_KEY_ID=your_aws_access_key
STORAGE_SECRET_ACCESS_KEY=your_aws_secret_key
STORAGE_REGION=us-east-1
STORAGE_BUCKET=your-bucket-name

# Redis
REDIS_URL=redis://your-redis-cluster:6379
REDIS_PASSWORD=your_redis_password

# Search
NEXT_PUBLIC_ALGOLIA_APP_ID=your_algolia_app_id
ALGOLIA_SEARCH_API_KEY=your_algolia_search_key
ALGOLIA_ADMIN_API_KEY=your_algolia_admin_key

# Monitoring
NEXT_PUBLIC_LOGROCKET_APP_ID=your_logrocket_app_id
LOGROCKET_URL=https://your-logrocket-url

# Security
CORS_ORIGIN=https://your-domain.com
RATE_LIMIT_MAX=1000
RATE_LIMIT_WINDOW_MS=900000

# Deployment
VERCEL_URL=https://your-domain.com
VERCEL_PROJECT_ID=your_vercel_project_id

4. Create Environment Variable Validation

Create src/​lib/​env.ts:

import { z } from 'zod';

// Environment variable schema
const envSchema = z.object({
  // Database
  NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
  NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
  SUPABASE_SERVICE_ROLE_KEY: z.string().min(1),

  // Authentication
  NEXTAUTH_SECRET: z.string().min(32),
  NEXTAUTH_URL: z.string().url().optional(),
  NEXTAUTH_TRUST_HOST: z.string().optional(),

  // Application
  NEXT_PUBLIC_APP_URL: z.string().url(),
  NEXT_PUBLIC_APP_NAME: z.string().min(1),
  NEXT_PUBLIC_APP_VERSION: z.string().optional(),

  // API
  API_BASE_URL: z.string().url().optional(),
  API_TIMEOUT: z.string().transform(Number).pipe(z.number().min(1000)).optional(),

  // Feature Flags
  NEXT_PUBLIC_ENABLE_ANALYTICS: z.coerce.boolean(),
  NEXT_PUBLIC_ENABLE_DEBUG: z.coerce.boolean(),
  NEXT_PUBLIC_ENABLE_LOGGING: z.coerce.boolean(),

  // Third-party Services
  NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: z.string().optional(),
  NEXT_PUBLIC_SENTRY_DSN: z.string().url().optional(),
  NEXT_PUBLIC_HOTJAR_ID: z.string().optional(),

  // Email
  RESEND_API_KEY: z.string().min(1).optional(),
  EMAIL_FROM: z.string().email().optional(),

  // Payment
  STRIPE_PUBLISHABLE_KEY: z.string().min(1).optional(),
  STRIPE_SECRET_KEY: z.string().min(1).optional(),
  STRIPE_WEBHOOK_SECRET: z.string().min(1).optional(),

  // Storage
  NEXT_PUBLIC_STORAGE_URL: z.string().url().optional(),
  STORAGE_ACCESS_KEY_ID: z.string().min(1).optional(),
  STORAGE_SECRET_ACCESS_KEY: z.string().min(1).optional(),
  STORAGE_REGION: z.string().optional(),
  STORAGE_BUCKET: z.string().min(1).optional(),

  // Redis
  REDIS_URL: z.string().url().optional(),
  REDIS_PASSWORD: z.string().optional(),

  // Search
  NEXT_PUBLIC_ALGOLIA_APP_ID: z.string().min(1).optional(),
  ALGOLIA_SEARCH_API_KEY: z.string().min(1).optional(),
  ALGOLIA_ADMIN_API_KEY: z.string().min(1).optional(),

  // Monitoring
  NEXT_PUBLIC_LOGROCKET_APP_ID: z.string().optional(),
  LOGROCKET_URL: z.string().url().optional(),

  // Development Tools
  NEXT_PUBLIC_DEVTOOLS: z.coerce.boolean(),
  NEXT_PUBLIC_STORYBOOK_ENABLED: z.coerce.boolean(),

  // Security
  CORS_ORIGIN: z.string().optional(),
  RATE_LIMIT_MAX: z.coerce.number().optional(),
  RATE_LIMIT_WINDOW_MS: z.coerce.number().optional(),

  // Deployment
  VERCEL_URL: z.string().url().optional(),
  VERCEL_PROJECT_ID: z.string().optional(),
  BUILD_ID: z.string().optional(),

  // Testing
  TEST_DATABASE_URL: z.string().url().optional(),
  TEST_SUPABASE_ANON_KEY: z.string().min(1).optional(),
});

// Validate environment variables
function validateEnv() {
  try {
    return envSchema.parse(process.env);
  } catch (error) {
    if (error instanceof z.ZodError) {
      const errorMessages = error.errors.map(
        (err) => `${err.path.join('.')}: ${err.message}`
      );
      throw new Error(
        `Environment variable validation failed:\n${errorMessages.join('\n')}`
      );
    }
    throw error;
  }
}

// Export validated environment variables
export const env = validateEnv();

// Export types for use in components
export type Env = z.infer<typeof envSchema>;

5. Create Environment Variable Utilities

Create src/​lib/​env-utils.ts:

import { env } from './​env';

// Get environment variable with fallback
export function getEnvVar(key: keyof typeof env, fallback?: string): string {
  return env[key] || fallback || '';
}

// Check if feature is enabled
export function isFeatureEnabled(feature: 'analytics' | 'debug' | 'logging' | 'devtools' | 'storybook'): boolean {
  const featureMap = {
    analytics: env.NEXT_PUBLIC_ENABLE_ANALYTICS,
    debug: env.NEXT_PUBLIC_ENABLE_DEBUG,
    logging: env.NEXT_PUBLIC_ENABLE_LOGGING,
    devtools: env.NEXT_PUBLIC_DEVTOOLS,
    storybook: env.NEXT_PUBLIC_STORYBOOK_ENABLED,
  };
  return featureMap[feature] || false;
}

// Get database configuration
export function getDatabaseConfig() {
  return {
    url: env.NEXT_PUBLIC_SUPABASE_URL,
    anonKey: env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
    serviceKey: env.SUPABASE_SERVICE_ROLE_KEY,
  };
}

// Get authentication configuration
export function getAuthConfig() {
  return {
    secret: env.NEXTAUTH_SECRET,
    url: env.NEXTAUTH_URL || env.NEXT_PUBLIC_APP_URL,
    trustHost: env.NEXTAUTH_TRUST_HOST,
  };
}

// Get API configuration
export function getApiConfig() {
  return {
    baseUrl: env.API_BASE_URL || `${env.NEXT_PUBLIC_APP_URL}/​api`,
    timeout: env.API_TIMEOUT || 30000,
  };
}

// Get payment configuration
export function getPaymentConfig() {
  return {
    publishableKey: env.STRIPE_PUBLISHABLE_KEY,
    secretKey: env.STRIPE_SECRET_KEY,
    webhookSecret: env.STRIPE_WEBHOOK_SECRET,
  };
}

// Get storage configuration
export function getStorageConfig() {
  return {
    url: env.NEXT_PUBLIC_STORAGE_URL,
    accessKeyId: env.STORAGE_ACCESS_KEY_ID,
    secretAccessKey: env.STORAGE_SECRET_ACCESS_KEY,
    region: env.STORAGE_REGION,
    bucket: env.STORAGE_BUCKET,
  };
}

// Get monitoring configuration
export function getMonitoringConfig() {
  return {
    sentryDsn: env.NEXT_PUBLIC_SENTRY_DSN,
    logrocketAppId: env.NEXT_PUBLIC_LOGROCKET_APP_ID,
    logrocketUrl: env.LOGROCKET_URL,
    googleAnalyticsId: env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID,
    hotjarId: env.NEXT_PUBLIC_HOTJAR_ID,
  };
}

// Environment-specific helpers
export function isDevelopment() {
  return process.env.NODE_ENV === 'development';
}

export function isProduction() {
  return process.env.NODE_ENV === 'production';
}

export function isTest() {
  return process.env.NODE_ENV === 'test';
}

// Safe environment variable access
export function safeEnv<T>(getter: () => T, fallback: T): T {
  try {
    return getter();
  } catch {
    return fallback;
  }
}

// Environment variable validation for runtime
export function validateRequiredEnvVars() {
  const requiredVars = [
    'NEXT_PUBLIC_SUPABASE_URL',
    'NEXT_PUBLIC_SUPABASE_ANON_KEY',
    'NEXTAUTH_SECRET',
    'NEXT_PUBLIC_APP_URL',
  ];

  const missing = requiredVars.filter(varName => !process.env[varName]);

  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables: ${missing.join(', ')}`
    );
  }
}

6. Create Client-Side Environment Hook

Create src/​hooks/​use-env.ts:

'use client';

import { useState, useEffect } from 'react';
import { env, isDevelopment, isProduction, isTest } from '@/​lib/​env';

export function useEnv() {
  const [clientEnv, setClientEnv] = useState(env);

  useEffect(() => {
    // Only run on client side
    if (typeof window !== 'undefined') {
      setClientEnv(env);
    }
  }, []);

  return clientEnv;
}

export function useFeatureFlags() {
  const env = useEnv();

  return {
    analytics: env.NEXT_PUBLIC_ENABLE_ANALYTICS,
    debug: env.NEXT_PUBLIC_ENABLE_DEBUG,
    logging: env.NEXT_PUBLIC_ENABLE_LOGGING,
    devtools: env.NEXT_PUBLIC_DEVTOOLS,
    storybook: env.NEXT_PUBLIC_STORYBOOK_ENABLED,
  };
}

export function useAppConfig() {
  const env = useEnv();

  return {
    name: env.NEXT_PUBLIC_APP_NAME,
    url: env.NEXT_PUBLIC_APP_URL,
    version: env.NEXT_PUBLIC_APP_VERSION,
    isDevelopment,
    isProduction,
    isTest,
  };
}

7. Create Server-Side Environment Helper

Create src/​lib/​server-env.ts:

import { headers } from 'next/​headers';
import { env } from './​env';

// Get environment variables on server side
export function getServerEnv() {
  return env;
}

// Get request-specific environment
export function getRequestEnv() {
  const headersList = headers();
  
  return {
    ...env,
    // Add request-specific environment variables
    requestUrl: headersList.get('x-request-url'),
    userAgent: headersList.get('user-agent'),
    host: headersList.get('host'),
    protocol: headersList.get('x-forwarded-proto') || 'http',
  };
}

// Validate environment for API routes
export function validateApiEnv() {
  validateRequiredEnvVars();
  
  return {
    database: getDatabaseConfig(),
    auth: getAuthConfig(),
    api: getApiConfig(),
  };
}

// Validate environment for server components
export function validateServerEnv() {
  validateRequiredEnvVars();
  
  return {
    database: getDatabaseConfig(),
    auth: getAuthConfig(),
    monitoring: getMonitoringConfig(),
  };
}

8. Create Environment Variable Documentation

Create docs/​environment-variables.md:

# Environment Variables

This document describes all environment variables used in the Zeus framework.

## Required Variables

### Database
- `NEXT_PUBLIC_SUPABASE_URL` - Supabase project URL
- `NEXT_PUBLIC_SUPABASE_ANON_KEY` - Supabase anonymous key
- `SUPABASE_SERVICE_ROLE_KEY` - Supabase service role key

### Authentication
- `NEXTAUTH_SECRET` - Secret for NextAuth.js (must be at least 32 characters)

### Application
- `NEXT_PUBLIC_APP_URL` - Application URL
- `NEXT_PUBLIC_APP_NAME` - Application name

## Optional Variables

### Feature Flags
- `NEXT_PUBLIC_ENABLE_ANALYTICS` - Enable analytics tracking (default: false)
- `NEXT_PUBLIC_ENABLE_DEBUG` - Enable debug mode (default: false)
- `NEXT_PUBLIC_ENABLE_LOGGING` - Enable logging (default: true)

### Third-party Services
- `NEXT_PUBLIC_GOOGLE_ANALYTICS_ID` - Google Analytics measurement ID
- `NEXT_PUBLIC_SENTRY_DSN` - Sentry error tracking DSN
- `NEXT_PUBLIC_HOTJAR_ID` - Hotjar user feedback ID

### Development Tools
- `NEXT_PUBLIC_DEVTOOLS` - Enable development tools (default: false)
- `NEXT_PUBLIC_STORYBOOK_ENABLED` - Enable Storybook (default: false)

## Environment-Specific Files

### Development (.env.development.local)
Used for local development. Contains development database URLs and debug settings.

### Test (.env.test.local)
Used for testing. Contains test database URLs and minimal feature flags.

### Production (.env.production.local)
Used for production deployment. Contains production URLs and API keys.

## Security Notes

- Never commit `.env.local` files to version control
- Use different keys for development, staging, and production
- Rotate secrets regularly
- Use environment-specific files for different deployment environments
- Validate all environment variables at startup

## Adding New Variables

1. Add the variable to the appropriate `.env.example` file
2. Update the Zod schema in `src/​lib/​env.ts`
3. Add validation logic if needed
4. Update this documentation

## Troubleshooting

### Missing Variables
If you see errors about missing environment variables:
1. Check that you have the correct `.env.local` file
2. Verify all required variables are set
3. Run `npm run validate-env` to check configuration

### Invalid Values
If environment variables fail validation:
1. Check the format requirements in the schema
2. Verify URLs are properly formatted
3. Ensure boolean values are "true" or "false"
4. Check that required minimum lengths are met

9. Create Environment Validation Script

Create scripts/​validate-env.js:

#!/​usr/​bin/​env node

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

// ANSI color codes
const colors = {
  reset: '\x1b[0m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
};

function colorLog(message, color = 'reset') {
  console.log(`${colors[color]}${message}${colors.reset}`);
}

function validateEnvironmentFiles() {
  colorLog('\n🔍 Validating environment files...', 'blue');
  
  const requiredFiles = [
    '.env.example',
    '.env.development.example',
    '.env.test.example',
    '.env.production.example',
  ];
  
  let allValid = true;
  
  requiredFiles.forEach(file => {
    if (fs.existsSync(file)) {
      colorLog(`✅ ${file} exists`, 'green');
    } else {
      colorLog(`❌ ${file} missing`, 'red');
      allValid = false;
    }
  });
  
  return allValid;
}

function validateLocalEnvFiles() {
  colorLog('\n🔍 Checking local environment files...', 'blue');
  
  const localFiles = [
    '.env.local',
    '.env.development.local',
    '.env.test.local',
    '.env.production.local',
  ];
  
  let hasLocalFiles = false;
  
  localFiles.forEach(file => {
    if (fs.existsSync(file)) {
      colorLog(`⚠️  ${file} exists (should not be committed)`, 'yellow');
      hasLocalFiles = true;
    } else {
      colorLog(`ℹ️  ${file} not found (expected for local development)`, 'cyan');
    }
  });
  
  return hasLocalFiles;
}

function validateRequiredVars() {
  colorLog('\n🔍 Validating required environment variables...', 'blue');
  
  try {
    // Try to import and validate the env schema
    const { env } = require('../​src/​lib/​env');
    colorLog('✅ Environment variables validated successfully', 'green');
    return true;
  } catch (error) {
    colorLog('❌ Environment variable validation failed:', 'red');
    colorLog(error.message, 'red');
    return false;
  }
}

function checkGitIgnore() {
  colorLog('\n🔍 Checking .gitignore configuration...', 'blue');
  
  if (!fs.existsSync('.gitignore')) {
    colorLog('❌ .gitignore file not found', 'red');
    return false;
  }
  
  const gitignore = fs.readFileSync('.gitignore', 'utf8');
  const requiredIgnores = [
    '.env.local',
    '.env.development.local',
    '.env.test.local',
    '.env.production.local',
  ];
  
  let allIgnored = true;
  
  requiredIgnores.forEach(pattern => {
    if (gitignore.includes(pattern)) {
      colorLog(`✅ ${pattern} is ignored`, 'green');
    } else {
      colorLog(`❌ ${pattern} is not ignored`, 'red');
      allIgnored = false;
    }
  });
  
  return allIgnored;
}

function main() {
  colorLog('🚀 Environment Variable Validation', 'magenta');
  colorLog('===================================', 'magenta');
  
  const checks = [
    validateEnvironmentFiles,
    validateLocalEnvFiles,
    validateRequiredVars,
    checkGitIgnore,
  ];
  
  let passed = 0;
  let failed = 0;
  
  for (const check of checks) {
    try {
      if (check()) {
        passed++;
      } else {
        failed++;
      }
    } catch (error) {
      colorLog(`❌ Check failed with error: ${error.message}`, 'red');
      failed++;
    }
  }
  
  colorLog('\n📊 Validation Summary', 'magenta');
  colorLog('==================', 'magenta');
  colorLog(`✅ Passed: ${passed}`, 'green');
  colorLog(`❌ Failed: ${failed}`, 'red');
  colorLog(`📈 Success Rate: ${((passed / (passed + failed)) * 100).toFixed(1)}%`, 
    failed === 0 ? 'green' : 'yellow');
  
  if (failed > 0) {
    colorLog('\n❌ Environment validation failed! Please fix the issues above.', 'red');
    process.exit(1);
  } else {
    colorLog('\n✅ All environment validations passed!', 'green');
    process.exit(0);
  }
}

if (require.main === module) {
  main();
}

module.exports = { validateEnvironmentFiles, validateLocalEnvFiles, validateRequiredVars };

10. Update Package.json Scripts

Update package.json scripts:

{
  "scripts": {
    "validate-env": "node scripts/​validate-env.js",
    "env:setup": "cp .env.example .env.local && echo 'Environment variables configured. Please update .env.local with your values.'",
    "env:dev": "cp .env.development.example .env.development.local && echo 'Development environment configured.'",
    "env:test": "cp .env.test.example .env.test.local && echo 'Test environment configured.'",
    "env:prod": "cp .env.production.example .env.production.local && echo 'Production environment configured.'",
    "env:check": "npm run validate-env"
  }
}

Code Examples

Using Environment Variables in Components

// Client-side component
'use client';

import { useEnv, useFeatureFlags } from '@/​hooks/​use-env';

export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
  const { NEXT_PUBLIC_GOOGLE_ANALYTICS_ID } = useEnv();
  const { analytics } = useFeatureFlags();

  if (!analytics || !NEXT_PUBLIC_GOOGLE_ANALYTICS_ID) {
    return <>{children}</>;
  }

  return (
    <>
      <script
        async
        src={`https://www.googletagmanager.com/gtag/js?id=${NEXT_PUBLIC_GOOGLE_ANALYTICS_ID}`}
      />
      <script
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${NEXT_PUBLIC_GOOGLE_ANALYTICS_ID}');
          `,
        }}
      />
      {children}
    </>
  );
}

Server-Side Usage

// API route
import { NextRequest, NextResponse } from 'next/​server';
import { validateApiEnv } from '@/​lib/​server-env';

export async function GET(request: NextRequest) {
  const env = validateApiEnv();
  
  // Use environment variables
  const databaseUrl = env.database.url;
  const anonKey = env.database.anonKey;
  
  // Your API logic here
  return NextResponse.json({ message: 'API is working' });
}

// Server component
import { validateServerEnv } from '@/​lib/​server-env';

export default async function ServerComponent() {
  const env = validateServerEnv();
  
  return (
    <div>
      <h1>Server Component</​h1>
      <p>App: {env.NEXT_PUBLIC_APP_NAME}</​p>
      <p>Version: {env.NEXT_PUBLIC_APP_VERSION}</​p>
    </​div>
  );
}

Conditional Feature Implementation

// Feature flag usage
import { isFeatureEnabled } from '@/​lib/​env-utils';

export function DebugPanel() {
  if (!isFeatureEnabled('debug')) {
    return null;
  }
  
  return (
    <div className="debug-panel">
      <h3>Debug Information</​h3>
      <p>Debug mode is enabled</​p>
    </​div>
  );
}

export function Logger() {
  const shouldLog = isFeatureEnabled('logging');
  
  const log = (message: string, data?: any) => {
    if (shouldLog) {
      console.log(`[LOG] ${message}`, data);
    }
  };
  
  return { log };
}

Configuration Templates

Complete Environment Variable Schema

import { z } from 'zod';

export const envSchema = z.object({
  // Database
  NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
  NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
  SUPABASE_SERVICE_ROLE_KEY: z.string().min(1),

  // Authentication
  NEXTAUTH_SECRET: z.string().min(32),
  NEXTAUTH_URL: z.string().url().optional(),
  NEXTAUTH_TRUST_HOST: z.string().optional(),

  // Application
  NEXT_PUBLIC_APP_URL: z.string().url(),
  NEXT_PUBLIC_APP_NAME: z.string().min(1),
  NEXT_PUBLIC_APP_VERSION: z.string().optional(),

  // Feature Flags
  NEXT_PUBLIC_ENABLE_ANALYTICS: z.coerce.boolean(),
  NEXT_PUBLIC_ENABLE_DEBUG: z.coerce.boolean(),
  NEXT_PUBLIC_ENABLE_LOGGING: z.coerce.boolean(),

  // Development Tools
  NEXT_PUBLIC_DEVTOOLS: z.coerce.boolean(),
  NEXT_PUBLIC_STORYBOOK_ENABLED: z.coerce.boolean(),
});

Best Practices

  1. Never commit secrets - Use .env.local files
  2. Validate at startup - Fail fast if required vars missing
  3. Use environment-specific files - Separate dev/​test/​prod configs
  4. Document all variables - Clear documentation for team
  5. Use TypeScript validation - Type-safe environment access
  6. Implement feature flags - Control functionality without deployment
  7. Rotate secrets regularly - Security best practice
  8. Use different keys per environment - Isolation

Stop Conditions

STOP and report if:

  • Environment validation fails
  • Required variables missing
  • Invalid variable formats
  • Git ignore configuration issues

Expected Outcomes:

  • All environment variables validated
  • Required variables present
  • Proper file structure in place
  • Git ignore configured correctly
  • Validation scripts functional

Verification Checklist

  • All example environment files created
  • Environment variable schema defined
  • Validation utilities implemented
  • Client-side hooks working
  • Server-side validation working
  • Git ignore configured
  • Validation script functional
  • Documentation complete
  • Package.json scripts updated
  • No sensitive files tracked

Version: 1.0.0 Last Updated: 2026-01-31 Skill Category: Architecture - Scaffolding