環境変数
Create T3 App は Zod↗ を使用して、src/env.js
にいくつかの追加ロジックを提供することにより、実行時および構築時に環境変数の検証を行います。
env.js
要約; 環境変数を追加する場合は、.env
に追加するとともに、src/env.js
にバリデーターを定義する必要があります。
このファイルは、スキーマと、オブジェクトの検証ロジックおよび再構築の、2 つの部分に分かれています。検証ロジックは触る必要がありません。
const server = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
});
const client = z.object({
// NEXT_PUBLIC_CLIENTVAR: z.string(),
});
const processEnv = {
NODE_ENV: process.env.NODE_ENV,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
};
サーバースキーマ
サーバーサイドの環境変数スキーマをここで定義します。
重要なシークレットがクライアント側に漏れないようにするため、ここでのキーには
NEXT_PUBLIC
の接頭辞をつけないようにしてください。
クライアントスキーマ
クライアント側の環境変数のスキーマをここで定義します。
クライアントに公開するには接頭辞 NEXT_PUBLIC
を付ける必要があります。接頭辞を付けない場合、検証が失敗するので不正な構成を検出できます。
processEnv オブジェクト
ここで process.env
を再構築します。
Zod スキーマを解析できる JavaScript オブジェクトが必要で、Next.js が環境変数を扱う方法のため、通常のオブジェクトのように process.env を再構築できません。そのため、手動で行う必要があります
TypeScript は、両方のスキーマからすべてのキーを再構築したことを確認するのに役立ちます。
// ❌ This doesn't work, we need to destruct it manually
const schema = z.object({
NEXT_PUBLIC_WS_KEY: z.string(),
});
const validated = schema.parse(process.env);
バリデーションロジック
興味のある読者のために:
高度な話題: バリデーションロジック
環境(サーバーまたはクライアント)に応じて、両方のスキーマが検証されるのか、クライアントのスキーマだけが検証されるのかが決まります。つまり、サーバーの環境変数が未定義であっても、バリデーションが失敗することはありません。つまり、環境変数のエントリーポイントを 1 つにすることができます。
// src/env.js
const isServer = typeof window === "undefined";
const merged = server.merge(client);
const parsed = isServer
? merged.safeParse(processEnv) // <-- on server, validate all
: client.safeParse(processEnv); // <-- on client, validate only client
if (parsed.success === false) {
console.error(
"❌ Invalid environment variables:\n",
...formatErrors(parsed.error.format()),
);
throw new Error("Invalid environment variables");
}
そして、プロキシオブジェクトを使って、クライアントでサーバーサイドの環境変数にアクセスしようとすると、エラーを投げるようにしています。
// src/env.js
// proxy allows us to remap the getters
export const env = new Proxy(parsed.data, {
get(target, prop) {
if (typeof prop !== "string") return undefined;
// on the client we only allow NEXT_PUBLIC_ variables
if (!isServer && !prop.startsWith("NEXT_PUBLIC_"))
throw new Error(
"❌ Attempted to access serverside environment variable on the client",
);
return target[prop]; // <-- otherwise, return the value
},
});
環境変数の使用
環境変数を使いたいときは、env.js
からインポートして、通常と同じように使うことができます。これをクライアントでインポートして、サーバー側の環境変数にアクセスしようとすると、ランタイムエラーが発生します。
import { env } from "../../env.js";
// `env` is fully typesafe and provides autocompletion
const dbUrl = env.DATABASE_URL;
import { env } from "../env.js";
// ❌ This will throw a runtime error
const dbUrl = env.DATABASE_URL;
// ✅ This is fine
const wsKey = env.NEXT_PUBLIC_WS_KEY;
.env.example
デフォルトの .env
ファイルはバージョンコントロールにコミットされないので、初期構成プロジェクトには.env.example
ファイルも用意しました。このファイルは、シークレット情報が削除された .env
ファイルのコピーを保存しておくことができます。これは必須ではありませんが、貢献者が自分の環境をできるだけ簡単に立ち上げられるようにするために、example を最新に保つことをお勧めします。
Next.js などのいくつかのフレームワークやビルドツールでは、シークレット情報を .env.local
ファイルに保存し、 .env
ファイルをプロジェクトにコミットすることを推奨するものがあります。しかしこれだと誤ってプロジェクトにシークレット情報をコミットしてしまうかもしれないため、あまりお勧めできません。その代わりに、シークレット情報を .env
に保存し、 .env
ファイルを .gitignore
に保存し、 .env.example
ファイルのみをプロジェクトにコミットすることを推奨します。
環境変数を追加する
プロジェクトが必要とする環境変数がない状態でビルドが完了しないようにするために、2 箇所 に新しい環境変数を追加する必要があります:
📄 .env
: 通常の.env
ファイルに入力するように、環境変数を入力します(例:KEY=VALUE
)。
📄 env.js
:Zod スキーマを定義することで、環境変数に適切な検証ロジックを追加します。(例:KEY: z.string()
)。そして、環境変数を process.env
から processEnv
オブジェクトに再構築します(例:KEY: process.env.KEY
)。
オプションで、.env.example
を最新化しておいても良いでしょう:
📄 .env.example
:環境変数を入力します。ただし、シークレット値は含めないように注意してください。(例: KEY=VALUE
or KEY=
)
例
サーバーサイドの環境変数として、Twitter API Token を追加したい。
- 環境変数を
.env
に追加する:
TWITTER_API_TOKEN=1234567890
- 環境変数を
env.js
に追加する:
export const server = z.object({
// ...
TWITTER_API_TOKEN: z.string(),
});
export const processEnv = {
// ...
TWITTER_API_TOKEN: process.env.TWITTER_API_TOKEN,
};
- オプション: 環境変数を
.env.example
に追加しますが、トークン値自体は含めないようにします。
TWITTER_API_TOKEN=