← 中文资源

简体中文版本

Dotenv 环境配置分层加载

按共享默认、环境专属文件、进程环境三层从低到高加载配置:显式覆盖规则、必填项启动即校验、最终冻结为只读配置对象。

阅读英文原文

示例说明

环境间的差异配置如果靠口口相传必然出错。分层加载给出确定规则:先读共享默认文件,再读当前环境专属文件覆盖差异项,容器平台注入的进程环境天然最高优先级。启动时校验必填变量,缺失直接退出,配置问题在部署阶段暴露而不是运行深处。

技术要点

  • 加载顺序即覆盖优先级
  • 必填变量缺失在启动时快速失败
  • Object.freeze 防止运行期篡改配置

代码解读

dotenv 的 config 把文件键值写入 process.env,后加载的文件按顺序覆盖前面同名的值;quiet 抑制多余的加载日志。settings 把扁平的环境变量整理成带类型的嵌套结构,featureFlags 支持逗号分隔列表解析,最后冻结防止业务代码偷偷改配置。

使用建议

默认文件提交进仓库,环境专属文件加入 gitignore 并提供模板。密钥类配置走平台密钥管理而不是文件。配置对象全项目单例导出,禁止散落的二次读取。

代码示例

import { config } from 'dotenv';

const ENV = process.env.NODE_ENV ?? 'development';

// 优先级从低到高:共享默认 → 环境专属 → 容器注入的进程环境
config({ path: '.env.defaults', quiet: true });
config({ path: `.env.${ENV}`, quiet: true });

const layered = { ...process.env };

const required = ['DATABASE_URL', 'REDIS_URL'];
const missing = required.filter((key) => !layered[key]);
if (missing.length > 0) {
  console.error('missing required env vars:', missing.join(', '));
  process.exit(1);
}

export const settings = Object.freeze({
  env: ENV,
  databaseUrl: layered.DATABASE_URL,
  redisUrl: layered.REDIS_URL,
  featureFlags: (layered.FEATURE_FLAGS ?? '').split(',').filter(Boolean),
  http: {
    port: Number(layered.PORT ?? 3000),
    bodyLimitMb: Number(layered.BODY_LIMIT_MB ?? 1),
  },
});

console.log('config resolved for', settings.env, 'port', settings.http.port);