为什么我构建了 nevr-env —— 以及为什么 process.env 值得更好的对待

发布: (2026年2月12日 GMT+8 13:19)
7 分钟阅读
原文: Dev.to

请提供您希望翻译的完整文本(除源码链接外的内容),我将为您翻译成简体中文并保留原始的格式、Markdown 语法以及技术术语。谢谢!

环境变量的问题

我已经厌倦了应用崩溃、机密泄露以及在 Slack 上复制粘贴 .env 文件。

每个开发者都有这样的时刻:

  1. 周五部署。CI 通过。你带着成就感回家。
  2. 收到一条提示:“生产环境中的应用崩溃了。”

罪魁祸首?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()
AIopenai()
邮件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

初始化向导会检测您的框架,查找正在运行的服务,并生成完整的配置。

链接

如果你曾因缺少环境变量而浪费生产时间,我很想听听你的故事。如果 nevr-env 为你解决了这个问题,在 GitHub 上给它点个星星将意义非凡。

由 Yalelet Dessalegn 在 nevr‑ts 生态系统中构建。

0 浏览
Back to Blog

相关文章

阅读更多 »