environment-setup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseEnvironment Configuration
环境配置
When to use this skill
何时使用该技能
- 신규 프로젝트: 초기 환경 설정
- 다중 환경: dev, staging, production 분리
- 팀 협업: 일관된 환경 공유
- 新项目:初始环境配置
- 多环境:dev、staging、production环境隔离
- 团队协作:共享一致的环境
Instructions
操作步骤
Step 1: .env 파일 구조
步骤1: .env文件结构
.env.example (템플릿):
bash
undefined.env.example(模板):
bash
undefinedApplication
Application
NODE_ENV=development
PORT=3000
APP_URL=http://localhost:3000
NODE_ENV=development
PORT=3000
APP_URL=http://localhost:3000
Database
Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
Redis
Redis
REDIS_URL=redis://localhost:6379
REDIS_TTL=3600
REDIS_URL=redis://localhost:6379
REDIS_TTL=3600
Authentication
Authentication
JWT_ACCESS_SECRET=change-me-in-production-min-32-characters
JWT_REFRESH_SECRET=change-me-in-production-min-32-characters
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d
JWT_ACCESS_SECRET=change-me-in-production-min-32-characters
JWT_REFRESH_SECRET=change-me-in-production-min-32-characters
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
External APIs
External APIs
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_PUBLISHABLE_KEY=pk_test_xxx
AWS_ACCESS_KEY_ID=AKIAXXXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxx
AWS_REGION=us-east-1
AWS_S3_BUCKET=myapp-uploads
STRIPE_SECRET_KEY=sk_test_xxx
STRIPE_PUBLISHABLE_KEY=pk_test_xxx
AWS_ACCESS_KEY_ID=AKIAXXXXXXXX
AWS_SECRET_ACCESS_KEY=xxxxxxxx
AWS_REGION=us-east-1
AWS_S3_BUCKET=myapp-uploads
Monitoring
Monitoring
SENTRY_DSN=https://xxx@sentry.io/xxx
LOG_LEVEL=info
SENTRY_DSN=https://xxx@sentry.io/xxx
LOG_LEVEL=info
Feature Flags
Feature Flags
ENABLE_2FA=false
ENABLE_ANALYTICS=true
**.env.local** (개발자별):
```bashENABLE_2FA=false
ENABLE_ANALYTICS=true
**.env.local**(开发者专属):
```bash개발자 개인 설정 (.gitignore에 추가)
开发者个人配置(需加入.gitignore)
DATABASE_URL=postgresql://localhost:5432/myapp_dev
LOG_LEVEL=debug
**.env.production**:
```bash
NODE_ENV=production
PORT=8080
APP_URL=https://myapp.com
DATABASE_URL=${DATABASE_URL} # 환경변수에서 주입
REDIS_URL=${REDIS_URL}
JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET}
JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET}
LOG_LEVEL=warn
ENABLE_2FA=trueDATABASE_URL=postgresql://localhost:5432/myapp_dev
LOG_LEVEL=debug
**.env.production**:
```bash
NODE_ENV=production
PORT=8080
APP_URL=https://myapp.com
DATABASE_URL=${DATABASE_URL} # 从环境变量注入
REDIS_URL=${REDIS_URL}
JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET}
JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET}
LOG_LEVEL=warn
ENABLE_2FA=trueStep 2: Type-Safe 환경변수 (TypeScript)
步骤2: 类型安全的环境变量(TypeScript)
config/env.ts:
typescript
import { z } from 'zod';
import dotenv from 'dotenv';
// Load .env file
dotenv.config();
// Define schema
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
JWT_ACCESS_SECRET: z.string().min(32),
JWT_REFRESH_SECRET: z.string().min(32),
SMTP_HOST: z.string(),
SMTP_PORT: z.coerce.number(),
SMTP_USER: z.string().email(),
SMTP_PASSWORD: z.string(),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
});
// Validate and export
export const env = envSchema.parse(process.env);
// Usage:
// import { env } from './config/env';
// console.log(env.DATABASE_URL); // Type-safe!에러 처리:
typescript
try {
const env = envSchema.parse(process.env);
} catch (error) {
if (error instanceof z.ZodError) {
console.error('❌ Invalid environment variables:');
error.errors.forEach((err) => {
console.error(` - ${err.path.join('.')}: ${err.message}`);
});
process.exit(1);
}
}config/env.ts:
typescript
import { z } from 'zod';
import dotenv from 'dotenv';
// Load .env file
dotenv.config();
// Define schema
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
JWT_ACCESS_SECRET: z.string().min(32),
JWT_REFRESH_SECRET: z.string().min(32),
SMTP_HOST: z.string(),
SMTP_PORT: z.coerce.number(),
SMTP_USER: z.string().email(),
SMTP_PASSWORD: z.string(),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
});
// Validate and export
export const env = envSchema.parse(process.env);
// Usage:
// import { env } from './config/env';
// console.log(env.DATABASE_URL); // Type-safe!错误处理:
typescript
try {
const env = envSchema.parse(process.env);
} catch (error) {
if (error instanceof z.ZodError) {
console.error('❌ Invalid environment variables:');
error.errors.forEach((err) => {
console.error(` - ${err.path.join('.')}: ${err.message}`);
});
process.exit(1);
}
}Step 3: 환경별 Config 파일
步骤3: 分环境配置文件
config/index.ts:
typescript
interface Config {
env: string;
port: number;
database: {
url: string;
pool: { min: number; max: number };
};
jwt: {
accessSecret: string;
refreshSecret: string;
accessExpiry: string;
refreshExpiry: string;
};
features: {
enable2FA: boolean;
enableAnalytics: boolean;
};
}
const config: Config = {
env: process.env.NODE_ENV || 'development',
port: parseInt(process.env.PORT || '3000'),
database: {
url: process.env.DATABASE_URL!,
pool: {
min: parseInt(process.env.DATABASE_POOL_MIN || '2'),
max: parseInt(process.env.DATABASE_POOL_MAX || '10'),
},
},
jwt: {
accessSecret: process.env.JWT_ACCESS_SECRET!,
refreshSecret: process.env.JWT_REFRESH_SECRET!,
accessExpiry: process.env.JWT_ACCESS_EXPIRY || '15m',
refreshExpiry: process.env.JWT_REFRESH_EXPIRY || '7d',
},
features: {
enable2FA: process.env.ENABLE_2FA === 'true',
enableAnalytics: process.env.ENABLE_ANALYTICS !== 'false',
},
};
// Validate required fields
const requiredEnvVars = [
'DATABASE_URL',
'JWT_ACCESS_SECRET',
'JWT_REFRESH_SECRET',
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`);
}
}
export default config;config/index.ts:
typescript
interface Config {
env: string;
port: number;
database: {
url: string;
pool: { min: number; max: number };
};
jwt: {
accessSecret: string;
refreshSecret: string;
accessExpiry: string;
refreshExpiry: string;
};
features: {
enable2FA: boolean;
enableAnalytics: boolean;
};
}
const config: Config = {
env: process.env.NODE_ENV || 'development',
port: parseInt(process.env.PORT || '3000'),
database: {
url: process.env.DATABASE_URL!,
pool: {
min: parseInt(process.env.DATABASE_POOL_MIN || '2'),
max: parseInt(process.env.DATABASE_POOL_MAX || '10'),
},
},
jwt: {
accessSecret: process.env.JWT_ACCESS_SECRET!,
refreshSecret: process.env.JWT_REFRESH_SECRET!,
accessExpiry: process.env.JWT_ACCESS_EXPIRY || '15m',
refreshExpiry: process.env.JWT_REFRESH_EXPIRY || '7d',
},
features: {
enable2FA: process.env.ENABLE_2FA === 'true',
enableAnalytics: process.env.ENABLE_ANALYTICS !== 'false',
},
};
// Validate required fields
const requiredEnvVars = [
'DATABASE_URL',
'JWT_ACCESS_SECRET',
'JWT_REFRESH_SECRET',
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`);
}
}
export default config;Step 4: 환경별 설정 파일
步骤4: 分环境配置文件
config/environments/development.ts:
typescript
export default {
logging: {
level: 'debug',
prettyPrint: true,
},
cors: {
origin: '*',
credentials: true,
},
rateLimit: {
enabled: false,
},
};config/environments/production.ts:
typescript
export default {
logging: {
level: 'warn',
prettyPrint: false,
},
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: true,
},
rateLimit: {
enabled: true,
windowMs: 15 * 60 * 1000,
max: 100,
},
};config/index.ts (통합):
typescript
import development from './environments/development';
import production from './environments/production';
const env = process.env.NODE_ENV || 'development';
const configs = {
development,
production,
test: development,
};
export const environmentConfig = configs[env];config/environments/development.ts:
typescript
export default {
logging: {
level: 'debug',
prettyPrint: true,
},
cors: {
origin: '*',
credentials: true,
},
rateLimit: {
enabled: false,
},
};config/environments/production.ts:
typescript
export default {
logging: {
level: 'warn',
prettyPrint: false,
},
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: true,
},
rateLimit: {
enabled: true,
windowMs: 15 * 60 * 1000,
max: 100,
},
};config/index.ts(整合版):
typescript
import development from './environments/development';
import production from './environments/production';
const env = process.env.NODE_ENV || 'development';
const configs = {
development,
production,
test: development,
};
export const environmentConfig = configs[env];Step 5: Docker 환경변수
步骤5: Docker环境变量
docker-compose.yml:
yaml
version: '3.8'
services:
app:
build: .
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
env_file:
- .env.local
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
redis:
image: redis:7-alpinedocker-compose.yml:
yaml
version: '3.8'
services:
app:
build: .
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
env_file:
- .env.local
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
redis:
image: redis:7-alpineOutput format
项目结构示例
project/
├── .env.example # 템플릿 (커밋)
├── .env # 로컬 (gitignore)
├── .env.local # 개발자별 (gitignore)
├── .env.production # 프로덕션 (gitignore or vault)
├── config/
│ ├── index.ts # 메인 설정
│ ├── env.ts # 환경변수 검증
│ └── environments/
│ ├── development.ts
│ ├── production.ts
│ └── test.ts
└── .gitignore.gitignore:
.env
.env.local
.env.*.local
.env.productionproject/
├── .env.example # 模板(需提交)
├── .env # 本地配置(需加入.gitignore)
├── .env.local # 开发者专属配置(需加入.gitignore)
├── .env.production # 生产环境配置(需加入.gitignore或存入密钥管理服务)
├── config/
│ ├── index.ts # 主配置文件
│ ├── env.ts # 环境变量验证
│ └── environments/
│ ├── development.ts
│ ├── production.ts
│ └── test.ts
└── .gitignore.gitignore:
.env
.env.local
.env.*.local
.env.productionConstraints
约束规则
필수 규칙 (MUST)
必须遵守的规则(MUST)
- .env.example 제공: 필요한 환경변수 목록
- 검증: 필수 환경변수 누락 시 에러
- .gitignore: .env 파일 절대 커밋하지 않음
- 提供.env.example文件: 列出所有必要的环境变量
- 验证机制: 若缺少必要环境变量则抛出错误
- Git忽略配置: 绝对不能提交.env文件
금지 사항 (MUST NOT)
禁止事项(MUST NOT)
- Secrets 커밋: .env 파일 절대 커밋하지 않음
- 하드코딩: 코드에 환경별 설정 하드코딩 금지
- 禁止提交密钥: 绝对不能提交.env文件
- 禁止硬编码: 禁止在代码中硬编码环境专属配置
Best practices
最佳实践
- 12 Factor App: 환경변수로 설정 관리
- Type Safety: Zod로 런타임 검증
- Secrets Management: AWS Secrets Manager, Vault 사용
- 遵循12 Factor App原则: 使用环境变量管理配置
- 类型安全: 使用Zod进行运行时验证
- 密钥管理: 使用AWS Secrets Manager或Vault等服务管理密钥
References
参考资料
Metadata
元数据
버전
版本
- 현재 버전: 1.0.0
- 최종 업데이트: 2025-01-01
- 호환 플랫폼: Claude, ChatGPT, Gemini
- 当前版本: 1.0.0
- 最后更新: 2025-01-01
- 兼容平台: Claude、ChatGPT、Gemini
태그
标签
#environment#configuration#env-variables#dotenv#config-management#utilities#environment#configuration#env-variables#dotenv#config-management#utilitiesExamples
示例
Example 1: Basic usage
示例1: 基础用法
<!-- Add example content here -->
<!-- Add example content here -->
Example 2: Advanced usage
示例2: 进阶用法
<!-- Add advanced example content here -->
<!-- Add example content here -->