Jump to content

環境変数

Create T3 App は Zod を使用して、src/env.jsにいくつかの追加ロジックを提供することにより、実行時および構築時に環境変数の検証を行います。

env.js

要約; 環境変数を追加する場合は、.envに追加するとともに、src/env.jsにバリデーターを定義する必要があります。

このファイルは、スキーマと、オブジェクトの検証ロジックおよび再構築の、2 つの部分に分かれています。検証ロジックは触る必要がありません。

env.js
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からインポートして、通常と同じように使うことができます。これをクライアントでインポートして、サーバー側の環境変数にアクセスしようとすると、ランタイムエラーが発生します。

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

// `env` is fully typesafe and provides autocompletion
const dbUrl = env.DATABASE_URL;
pages/index.tsx
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 を追加したい

  1. 環境変数を .env に追加する:
TWITTER_API_TOKEN=1234567890
  1. 環境変数を env.js に追加する:
export const server = z.object({
  // ...
  TWITTER_API_TOKEN: z.string(),
});

export const processEnv = {
  // ...
  TWITTER_API_TOKEN: process.env.TWITTER_API_TOKEN,
};
  1. オプション: 環境変数を .env.example に追加しますが、トークン値自体は含めないようにします。
TWITTER_API_TOKEN=