Skip to content
返回构建教程

环境配置

加载、验证、分层环境变量,让应用在缺配置时快速失败。

为什么

未定义的环境变量是'本地能跑、prod 挂'的头号原因——变量在你的 .env 里但不在平台面板里,应用在凌晨 3 点用 500 发现它。验证层(zod、envalid 或 pydantic)把它变成启动崩溃带清晰消息,所以部署在 CI 而非 prod 失败。分层(defaults < .env < .env.local < platform)让你把密钥排除 git 同时与团队共享非密钥配置。没有它,每个开发者维护个人 .env 漂移,入职要花一天'我需要哪些变量?'。

何时使用

应用读第一个环境变量时。用 zod 约 20-40 分钟。仅对零配置纯静态站可跳过。

如何做

1. 用 zod 定义 schema,列出每个变量的类型 + 默认值 + 描述
   - const schema = z.object({ DATABASE_URL: z.string().url(), PORT: z.coerce.number().default(3000) })

2. 启动时解析 process.env,导出类型化单例
   - const env = schema.parse(process.env)——缺第一个变量即抛错
   - 在一处调用(src/env.ts);所有人从那里 import

3. 创建 .env.example 含每个 key + 注释,提交它
   - 永不提交 .env;第 1 次提交就加进 .gitignore

4. 分层优先级:.env.defaults < .env < .env.local < 平台变量
   - 用 dotenv-flow 或 Next.js 内置分层
   - .env.local 存开发密钥(gitignore);平台存 prod 密钥

5. 快速失败:在模块顶层调用 env 解析,不在请求 handler 里
   - 缺变量应在启动时崩溃,而非第一个请求时

示例

// src/env.ts
import { z } from "zod";

const schema = z.object({
  DATABASE_URL: z.string().url(),
  NEXTAUTH_SECRET: z.string().min(32),
  NEXTAUTH_URL: z.string().url(),
  PORT: z.coerce.number().default(3000),
  NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
});

export const env = schema.parse(process.env);
// → 若 DATABASE_URL 缺失,应用启动即崩:
//   "Invalid input: DATABASE_URL: Required"

常见问题

  • ⚠在 20 个文件里直接读 process.env 而非一个模块——改变量名要全仓搜索。
  • ⚠把所有变量当字符串,PORT='3000' + 1 运行时得 '30001' 而非 3001。
  • ⚠把密钥放 .env 并提交'给团队用'——git 历史现在永远含 Stripe key。
  • ⚠启动时不验证,应用正常启动,第一次 DB 查询才崩,报晦涩连接错误。

最佳实践

  • ✓数字和布尔用 z.coerce,'PORT=3000' 直接变真数字无需手动 parseInt。
  • ✓加 CI 步骤用 schema 验证 .env.example——抓住你加到代码但忘了文档化的变量。
  • ✓错误 handler 里永不 log 整个 env 对象——你会把密钥泄漏给日志聚合器。
  • ✓prod 用密钥管理器(Doppler、Infisical)而非把值粘进平台面板——轮换变成配置变更而非部署。