环境配置与多环境
What — 是什么
环境配置是 Node.js 应用管理不同运行环境(开发/测试/生产)配置的方式,通过环境变量和配置文件实现配置与代码分离,确保敏感信息不入库。
核心概念:
- dotenv:从
.env文件加载环境变量到process.env,最简单的配置管理 - node-config:分层配置系统,按
NODE_ENV加载不同配置文件,支持合并覆盖 - 环境变量:
process.env中的配置,12-Factor App 推荐方式 - 配置验证:启动时校验必要的环境变量是否存在和合法(zod/joi)
- 密钥管理:敏感配置(数据库密码/API Key/JWT Secret)的管理策略
- 多环境:development/staging/production 环境的配置差异化
关键特性:
.env文件不提交到 Git(.gitignore中排除).env.example提交到 Git,记录必要的环境变量模板dotenv只在开发环境使用,生产环境由系统注入环境变量node-config支持配置继承(default.json → production.json 覆盖)- zod 在应用启动时验证环境变量,缺失或不合法直接报错
Why — 为什么
适用场景:
- 所有需要区分环境的 Node.js 项目
- 数据库连接字符串/API Key 等敏感配置
- 多环境部署(开发/测试/预发/生产)
对比配置方案:
| 维度 | dotenv | node-config | 硬编码 |
|---|---|---|---|
| 配置分离 | 是 | 是 | 否 |
| 多环境 | 手动切换 | 自动加载 | 代码判断 |
| 类型安全 | 无 | 无 | 无 |
| 验证 | 需额外库 | 需额外库 | 无 |
| 复杂度 | 低 | 中 | 无 |
优缺点:
- ✅ 优点:配置与代码分离、敏感信息不入库、环境切换方便
- ❌ 缺点:无类型安全、无变更通知、过多环境变量管理混乱
How — 怎么用
快速上手
npm install dotenv
// 开发环境加载 .env
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
# .env.example(提交到 Git)
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
REDIS_URL=redis://localhost:6379
JWT_SECRET=your-secret-key-at-least-32-chars
代码示例
node-config 分层配置 + zod 验证:
// config/default.json
{
"app": { "port": 3000, "name": "my-api" },
"database": { "pool": { "min": 2, "max": 10 } },
"redis": { "ttl": 3600 },
"jwt": { "expiresIn": "7d" }
}
// config/production.json(覆盖 default)
{
"app": { "port": 8080 },
"database": { "pool": { "min": 5, "max": 50 } },
"redis": { "ttl": 1800 }
}
// 使用
const config = require('config');
const port = config.get('app.port');
// env.ts — 环境变量验证
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
PORT: z.coerce.number().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default('7d'),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info')
});
const env = envSchema.parse(process.env);
export default env;
常见问题与踩坑
| 问题 | 原因 | 解决方案 |
|---|---|---|
| .env 泄露到 Git | 忘记加入 .gitignore | .gitignore 加 .env*,只提交 .env.example |
| 环境变量类型不对 | process.env 全是字符串 | z.coerce.number() 或 parseInt |
| Docker 中 .env 不生效 | 容器不读 .env 文件 | docker run --env-file .env 或 Compose env_file |
| 启动后才发现缺配置 | 没有启动时验证 | 用 zod 在 import 时验证 |
最佳实践
.env不入库,.env.example记录模板- 生产环境由 CI/CD 或 K8s 注入环境变量,不用 .env 文件
- 启动时用 zod 验证必要环境变量
- 敏感配置(密码/Key)只通过环境变量传递
- 不同环境的差异化配置用 node-config 分层
面试题
Q1: 12-Factor App 对配置的原则是什么?
12-Factor 第三条:“在环境中存储配置”(Store config in the environment)。原则:① 配置与代码严格分离——配置不硬编码在代码中;② 配置通过环境变量注入——不同环境只需改变环境变量;③ 敏感信息不入代码库——数据库密码/API Key 等只存在于运行环境中。判断标准:如果代码开源,是否需要修改任何配置?如果不需要,说明配置分离做得好。
Q2: dotenv 的工作原理?生产环境为什么不用?
dotenv 读取
.env文件,解析KEY=VALUE行,注入到process.env。生产环境不用因为:①.env文件是明文存储,服务器上不安全;② 容器化环境通过docker run -e或 K8s ConfigMap/Secret 注入更安全;③ 多实例部署时每个实例都要维护.env文件,不方便;④ CI/CD 流水线通过平台环境变量注入更可靠。dotenv 只用于本地开发便利。
相关链接: