为什么我构建了 nevr-env —— 以及为什么 process.env 值得更好的对待
请提供您希望翻译的完整文本(除源码链接外的内容),我将为您翻译成简体中文并保留原始的格式、Markdown 语法以及技术术语。谢谢!
环境变量的问题
我已经厌倦了应用崩溃、机密泄露以及在 Slack 上复制粘贴 .env 文件。
每个开发者都有这样的时刻:
- 周五部署。CI 通过。你带着成就感回家。
- 收到一条提示:“生产环境中的应用崩溃了。”
罪魁祸首?DATABASE_URL 从未设置。应用访问了 process.env.DATABASE_URL,得到 undefined,并悄悄地将其作为连接字符串传递。Postgres 对此并不满意。
我遇到过这种 bug 的次数比我愿意承认的要多。每次的解决办法都是一样的:在 .env.example 中再加一行,盼望队友阅读 README,然后继续前进。
为什么现有工具失效
- 启动时没有验证 –
process.env.PORT的类型是string | undefined。如果忘记了PORT,服务器会悄悄地在undefined上监听。 - 没有类型安全 –
process.env.ENABLE_CACHE是"true"(字符串),而不是true(布尔值)。每个开发者都要自己编写解析逻辑。 - 机密散布 – 团队通过 Slack 私信、Google 文档或更糟的方式共享机密。
.env.example总是过时的。 - 到处都是样板代码 – 新项目需要复制 Zod 模式并编写相同的
DATABASE_URL: z.string().url()、PORT: z.coerce.number()等。
t3‑env 差距
t3-env 是一次前进:使用 Zod 进行类型安全的环境变量验证。我使用过并且很喜欢。
但随着我的项目增多,问题显现:
// Every. Single. Project.
export const env = createEnv({
server: {
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
STRIPE_SECRET_KEY: z.string().startsWith("sk_"),
STRIPE_WEBHOOK_SECRET: z.string().startsWith("whsec_"),
OPENAI_API_KEY: z.string().startsWith("sk-"),
RESEND_API_KEY: z.string().startsWith("re_"),
// ... 20 more lines of the same patterns
},
});
- 我在八个项目中重复编写相同的 schema。当 Stripe 更改其密钥格式时,我必须更新所有项目。
- 新同事克隆仓库后运行
npm run dev,会看到一堆验证错误,并且需要花费 30 分钟来弄清楚每个错误对应的含义。
Source: …
介绍 nevr‑env
nevr-env 是一个 环境生命周期框架——不仅仅是验证,而是从搭建到生产监控的完整生命周期。
简化配置
import { createEnv } from "nevr-env";
import { postgres } from "nevr-env/plugins/postgres";
import { stripe } from "nevr-env/plugins/stripe";
import { openai } from "nevr-env/plugins/openai";
import { z } from "zod";
export const env = createEnv({
server: {
NODE_ENV: z.enum(["development", "production", "test"]),
API_SECRET: z.string().min(10),
},
plugins: [
postgres(),
stripe(),
openai(),
],
});
三个插件取代了 15 行以上的手动 schema。 每个插件都知道正确的格式,提供合适的校验,甚至包含自动发现(例如,自动检测正在运行的 Postgres 容器)。
交互式入职
当新开发者在缺少变量的情况下运行应用时:
$ npx nevr-env fix
他们会看到交互式向导,而不是一堆错误信息:
? DATABASE_URL is missing
This is: PostgreSQL connection URL
Format: postgresql://user:pass@host:port/db
> Paste your value: █
入职时间从“在 Slack 上找人询问”变为“一条命令搞定”。
加密密钥管理(Vault)
# 生成密钥(每个团队一次)
npx nevr-env vault keygen
# 将 .env 加密为 vault 文件
npx nevr-env vault push # 创建 .nevr-env.vault(可安全提交)
# 新同事拉取仓库并解密
npx nevr-env vault pull # 在本地生成 .env
- Vault 使用 AES‑256‑GCM 加密,配合 PBKDF2(600 K 次迭代)。
- 加密密钥永不进入仓库。
- 小团队不再需要 Slack 私信或付费的密钥管理 SaaS。
密钥扫描
$ npx nevr-env scan
Found 2 secrets in codebase:
CRITICAL src/config.ts:14 AWS Access Key (AKIA...)
HIGH lib/api.ts:8 Stripe Secret Key (sk_live_...)
在 CI 中运行,能够在密钥写入 Git 历史之前将其捕获——无需额外工具。
插件
| 类别 | 插件 |
|---|---|
| 数据库 | postgres(), redis(), supabase() |
| 认证 | clerk(), auth0(), better-auth(), nextauth() |
| 支付 | stripe() |
| AI | openai() |
| 邮件 | resend() |
| 云 | aws() |
| 预设 | vercel(), railway(), netlify() |
创建自定义插件
import { createPlugin } from "nevr-env";
import { z } from "zod";
export const myService = createPlugin({
name: "my-service",
schema: {
MY_API_KEY: z.string().min(1),
MY_API_URL: z.string().url(),
},
});
CLI 命令
| 命令 | 描述 |
|---|---|
init | 在你的项目中设置 nevr-env |
check | 验证所有环境变量(适用于 CI) |
fix | 交互式向导,用于缺失的变量 |
generate | 根据模式自动生成 .env.example |
types | 生成 env.d.ts 类型定义 |
scan | 在代码中查找泄露的密钥 |
diff | 比较不同版本之间的模式 |
rotate | 跟踪密钥轮换状态 |
ci | 生成 CI 配置(GitHub Actions、Vercel、Railway) |
dev | 验证并运行开发服务器 |
watch | 在 .env 更改时实时重新加载验证 |
vault | 加密密钥管理(keygen/push/pull/status) |
安装
pnpm add nevr-env zod
npx nevr-env init
初始化向导会检测您的框架,查找正在运行的服务,并生成完整的配置。
链接
- GitHub: https://github.com/nevr-ts/nevr-env
- npm: https://www.npmjs.com/package/nevr-env
- Docs: https://nevr-ts.github.io/nevr-env/
如果你曾因缺少环境变量而浪费生产时间,我很想听听你的故事。如果 nevr-env 为你解决了这个问题,在 GitHub 上给它点个星星将意义非凡。
由 Yalelet Dessalegn 在 nevr‑ts 生态系统中构建。