Environment Variables
> **Skill Purpose:** Secure environment variable and secrets management patterns
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:
- Define environment variable categories and schema
- Create validation patterns for required variables
- Establish secure storage and access patterns
- Set up environment-specific variable sets
- 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
- Never commit secrets - Use
.env.localfiles - Validate at startup - Fail fast if required vars missing
- Use environment-specific files - Separate dev/test/prod configs
- Document all variables - Clear documentation for team
- Use TypeScript validation - Type-safe environment access
- Implement feature flags - Control functionality without deployment
- Rotate secrets regularly - Security best practice
- 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
