# Env Config Setup

> Generate environment configuration files and validation schemas

- Skill: `tools-only/env-config-setup` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add tools-only/env-config-setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/env-config-setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/tools-only/env-config-setup

---

# Environment Config Setup

Generates environment configuration files (.env templates, validation schemas, and type-safe config loading) for multiple environments.

## What This Command Does

**Generated Configuration:**
-  .env.example (committed template)
-  .env.development, .env.production
-  Config validation schema (Zod)
-  Type-safe config loader
-  Secret management guidance
-  Docker environment setup

**Output:** Complete environment configuration system

**Time:** 2-3 minutes

---

## Usage

```bash
# Generate basic environment config
/env-config-setup

# Shortcut
/ecs --services database,redis,email

# With specific platform
/ecs --platform aws --features secrets-manager
```

---

## Generated Files

### **.env.example** (Template - Committed to Repo)

```bash
# Application
NODE_ENV=development
PORT=3000
APP_NAME=My Application
APP_URL=http://localhost:3000

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10

# Redis
REDIS_URL=redis://localhost:6379
REDIS_PREFIX=myapp:

# Authentication
JWT_SECRET=generate-random-32-char-secret-here
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=generate-random-32-char-refresh-secret
JWT_REFRESH_EXPIRES_IN=7d

# Email (SendGrid)
SENDGRID_API_KEY=SG.your-api-key-here
FROM_EMAIL=[email protected]

# AWS (Optional)
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_REGION=us-east-1
S3_BUCKET=your-bucket-name

# External APIs
STRIPE_SECRET_KEY=sk_test_your-stripe-key
STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret

# Monitoring
SENTRY_DSN=https://your-sentry-dsn
LOG_LEVEL=info

# Feature Flags
ENABLE_FEATURE_X=false
```

### **.env.development**

```bash
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://postgres:password@localhost:5432/myapp_dev
REDIS_URL=redis://localhost:6379
LOG_LEVEL=debug
```

### **.env.production**

```bash
NODE_ENV=production
PORT=8080
# Use environment variables or secrets manager for sensitive values
DATABASE_URL=${DATABASE_URL}
REDIS_URL=${REDIS_URL}
JWT_SECRET=${JWT_SECRET}
LOG_LEVEL=warn
```

### **config/env.ts** (Type-Safe Config Loader)

```typescript
import { z } from 'zod'
import dotenv from 'dotenv'

// Load appropriate .env file
const envFile = process.env.NODE_ENV === 'production'
  ? '.env.production'
  : '.env.development'

dotenv.config({ path: envFile })

// Define validation schema
const envSchema = z.object({
  // Application
  NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  PORT: z.coerce.number().min(1).max(65535).default(3000),
  APP_NAME: z.string().min(1),
  APP_URL: z.string().url(),

  // Database
  DATABASE_URL: z.string().url(),
  DATABASE_POOL_MIN: z.coerce.number().min(0).default(2),
  DATABASE_POOL_MAX: z.coerce.number().min(1).default(10),

  // Redis
  REDIS_URL: z.string().url(),
  REDIS_PREFIX: z.string().default(''),

  // Authentication
  JWT_SECRET: z.string().min(32),
  JWT_EXPIRES_IN: z.string().default('15m'),
  JWT_REFRESH_SECRET: z.string().min(32),
  JWT_REFRESH_EXPIRES_IN: z.string().default('7d'),

  // Email
  SENDGRID_API_KEY: z.string().startsWith('SG.'),
  FROM_EMAIL: z.string().email(),

  // AWS (optional)
  AWS_ACCESS_KEY_ID: z.string().optional(),
  AWS_SECRET_ACCESS_KEY: z.string().optional(),
  AWS_REGION: z.string().default('us-east-1'),
  S3_BUCKET: z.string().optional(),

  // External APIs
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
  STRIPE_WEBHOOK_SECRET: z.string().startsWith('whsec_'),

  // Monitoring
  SENTRY_DSN: z.string().url().optional(),
  LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'),

  // Feature Flags
  ENABLE_FEATURE_X: z.coerce.boolean().default(false)
})

// Parse and validate
const parsedEnv = envSchema.safeParse(process.env)

if (!parsedEnv.success) {
  console.error(' Invalid environment variables:')
  console.error(parsedEnv.error.flatten().fieldErrors)
  process.exit(1)
}

export const env = parsedEnv.data

// Type-safe access
export type Env = z.infer<typeof envSchema>
```

### **config/secrets.ts** (AWS Secrets Manager)

```typescript
import { SecretsManager } from '@aws-sdk/client-secrets-manager'

const client = new SecretsManager({ region: process.env.AWS_REGION })

export async function loadSecrets(secretName: string) {
  try {
    const response = await client.getSecretValue({ SecretId: secretName })
    return JSON.parse(response.SecretString || '{}')
  } catch (error) {
    console.error('Failed to load secrets:', error)
    throw error
  }
}

// Usage
const secrets = await loadSecrets('prod/myapp/secrets')
process.env.JWT_SECRET = secrets.JWT_SECRET
```

### **docker-compose.env.yml**

```yaml
version: '3.8'

services:
  app:
    build: .
    env_file:
      - .env.development
    environment:
      - NODE_ENV=development
      - PORT=3000
    ports:
      - "3000:3000"

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
      POSTGRES_DB: ${POSTGRES_DB:-myapp_dev}
    ports:
      - "5432:5432"
```

---

## Security Best Practices

**1. Never Commit Secrets:**
```bash
# .gitignore
.env
.env.local
.env.*.local
.env.production
*.key
*.pem
secrets/
```

**2. Use Secret Rotation:**
```bash
# Rotate secrets regularly
# Use AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault
# Example: Rotate JWT secrets every 30 days
```

**3. Least Privilege:**
```bash
# Only provide necessary permissions
# Use separate credentials for dev/staging/prod
# Implement role-based access control
```

**4. Environment Validation:**
```typescript
// Validate on startup
if (process.env.NODE_ENV === 'production') {
  if (!env.JWT_SECRET || env.JWT_SECRET.length < 32) {
    throw new Error('Production JWT_SECRET must be at least 32 characters')
  }
}
```

---

## Secret Generation

```bash
# Generate secure random secrets
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Or use openssl
openssl rand -hex 32

# For JWT secrets (base64)
openssl rand -base64 32
```

---

## Platform-Specific Setup

**Vercel:**
```bash
# Set environment variables via CLI
vercel env add DATABASE_URL production
vercel env add JWT_SECRET production
```

**Railway:**
```bash
# Environment variables in dashboard
# Or via railway.json
{
  "deploy": {
    "envVars": {
      "NODE_ENV": "production"
    }
  }
}
```

**AWS ECS:**
```json
{
  "containerDefinitions": [{
    "secrets": [
      {
        "name": "DATABASE_URL",
        "valueFrom": "arn:aws:secretsmanager:region:account:secret:name"
      }
    ]
  }]
}
```

---

## Related Commands

- `/auth-setup` - Generate authentication system
- `/project-scaffold` - Generate full project structure

---

**Manage secrets safely. Configure environments easily. Deploy confidently.** ️

