Jump to content

环境变量

通过在 env 目录下的一些额外配置文件,Create-T3-App 在运行时 和 编译时使用 Zod↗ 来验证你的环境变量:

📁 src/env

┣ 📄 client.mjs

┣ 📄 schema.mjs

┣ 📄 server.mjs

这些配置文件的内容乍看之下可能很吓人,但不必惊慌,它并非看起来那般复杂。让我们逐个分析,并展示添加额外环境变量的整个流程。

简而言之,如果你想要添加一个新的环境变量,你需要在 .env 中添加变量的同时,在 env/schema.mjs 里定义好对应的验证逻辑。

schema.mjs

你会在这个文件编写环境变量的验证逻辑。它包含了两个 schema,一个用于验证服务端的环境变量,一个用于验证客户端的环境变量,以及一个 clientEnv 对象。

env/schema.mjs
export const serverSchema = z.object({
  // DATABASE_URL: z.string().url(),
});

export const serverEnv = {
  // DATABASE_URL: process.env.DATABASE_URL,
};

export const clientSchema = z.object({
  // NEXT_PUBLIC_WS_KEY: z.string(),
});

export const clientEnv = {
  // NEXT_PUBLIC_WS_KEY: process.env.NEXT_PUBLIC_WS_KEY,
};

服务端 schema

在这里定义你项目服务端的环境变量。

确保在这里不要给变量添加前缀 NEXT_PUBLIC。 如果你添加了,验证会无法通过,这样可以帮你检测到无效的配置。

客户端 Schema

在这里定义你项目客户端的环境变量。

为了将它们暴露出来,你需要给他们添加前缀 NEXT_PUBLIC。如果你没有这么做,验证会无法通过,这样可以帮助你检测到无效的配置。

clientEnv 对象

在这里解构 process.env。

由于 Next.js 处理环境变量的方法,我们需要一个 JavaScript 对象来解析 Zod schema,你不能像处理一般对象一样直接解构 process.env,所以我们需要手动进行解构。

TypeScript 会确保你已经同时在 clientEnv 和 clientSchema 中都输入了 key。

// ❌ 这将不会生效,我们需要手动解构
const schema = z.object({
  NEXT_PUBLIC_WS_KEY: z.string(),
});

const validated = schema.parse(process.env);

server.mjs 和 client.mjs

验证会在这两个文件里进行,它们会将验证过的对象导出。你不应该修改这些文件。

使用环境变量

当你想要使用环境变量时,你可以从 env/client.mjs 或 env/server.mjs 文件中导入它们,这取决于你想在客户端还是服务端使用它们:

pages/api/hello.ts
import { env } from "../../env/server.mjs";

// `env` 完全类型安全并能提供自动完成
const dbUrl = env.DATABASE_URL;

.env.example

因为默认的 .env 文件并不会被提交到版本管理中,所以我们提供了 .env.example 文件,你可以将这个文件作为 .env 文件的复本,不过务必记得要移除敏感密钥。虽然将 env 内容同步到这个文件不是强制性的,但我们还是推荐及时更新这个文件,以便尽可能使贡献者们能快速使用环境变量。

一些框架和构建工具,例如 Next.js,会建议我们将密钥存储在 .env.local 文件,然后将 .env 文件提交到仓库里。实际上我们并不推荐这么做,因为这样很容易会导致我们不小心将密钥提交到仓库里。相反地,我们推荐你将密钥保存到 .env 文件里,然后将它添加到 .gitignore 中,然后仅将 .env.example 提交到你的仓库。

添加环境变量

为了确保你的应用只有在满足必要环境变量的情况才会完成构建,你将需要在两个地方添加环境变量:

📄 .env: 在这里输入环境变量,就像你之前在常规 .env 文件中做的那样,比如添加 KEY=VALUE

📄 schema.mjs: 在这里通过 Zod 定义验证 schema,例如 KEY: z.string(),给新加的环境变量添加适当的验证逻辑

可选地,你也可以修改 .env.example:

📄 .env.example: 输入你的环境变量,但是确保不要包含密钥信息,例如 KEY=VALUE,则把 VALUE 去掉只留 KEY=

示例

我想将我的推特 API 令牌作为服务端环境变量添加

  1. 在 .env 添加环境变量:
TWITTER_API_TOKEN=1234567890
  1. 在 schema.mjs 中添加环境变量:
export const serverSchema = z.object({
  // ...
  TWITTER_API_TOKEN: z.string(),
});

export const serverEnv = {
  // ...
  TWITTER_API_TOKEN: process.env.TWITTER_API_TOKEN,
};

注意: 一个空的字符串仍然是一个字符串,所以 z.string() 会认为它是一个有效值。如果你想要确保环境变量的值不能为空,你可以使用 z.string().min(1)。

  1. 可选的:将环境变量添加到 .env.example,但不包含令牌:
TWITTER_API_TOKEN=