# Vercel 環境変数・シークレット管理ガイド：3環境・NEXT_PUBLIC_の罠・OIDC鍵レス・型安全な境界

> Vercel公式に忠実な環境変数・シークレット管理ガイド。production/preview/developmentの3環境とブランチ別上書き、NEXT_PUBLIC_によるブラウザ露出の罠、64KB上限とEdge 5KB制限、vercel env pullでのローカル同期、システム環境変数、OIDC鍵レスによる外部クラウド接続、Zodでの型安全なenv境界までを実コードで解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: Vercel, セキュリティ, Next.js, TypeScript, 型安全, CI/CD, アーキテクチャ設計
- URL: https://tomodahinata.com/blog/vercel-environment-variables-secrets-oidc-management-guide
- カテゴリ: Vercel 本番運用
- 総合ガイド: https://tomodahinata.com/blog/vercel-production-platform-guide

## 要点

- Vercelの環境変数は3環境（production/preview/development）。値は保存時に暗号化され、変更は新しいデプロイにのみ反映される（既存デプロイは変わらない）。preview変数はブランチ別に上書きできる
- 最大の事故はNEXT_PUBLIC_接頭辞。この接頭辞の変数はビルド時にバンドルへ埋め込まれブラウザに露出する。APIキー・DB接続文字列・秘密鍵には絶対に付けない。クライアントで読む必要がある公開値だけに使う
- vercel env pullでローカル.envへ同期。vercel devは自動でdevelopment変数をメモリに読み込む。@vercel/speed-insightsや@vercel/analyticsはpackage.jsonの依存に入れる（グローバルだとエラー）
- 合計サイズはデプロイあたり64KB（Node.js/Python/Ruby/Go等）。Edgeランタイムは1変数5KBまで。JWT・証明書のような大きな値も64KB枠で扱える
- 外部クラウド（AWS等）へは長命アクセスキーを置かずOIDC鍵レスで一時クレデンシャルを得る。Fluid Computeのグローバル状態にリクエスト固有の秘密を残さない。envはZodで起動時に型検証して境界を固める

---

シークレットの取り扱いは、地味ですが**事故ると一発で致命傷**になる領域です。「API キーが GitHub に漏れた」「`NEXT_PUBLIC_` を付けたら本番のキーがブラウザに出ていた」——どれも数分で起きて、長く尾を引きます。

この記事は [Vercel 環境変数](https://vercel.com/docs/environment-variables)の公式仕様に忠実に、3環境の使い分け・`NEXT_PUBLIC_` の罠・OIDC 鍵レス・型安全な env 境界をまとめます。全体像は [Vercel 本番運用ガイド](/blog/vercel-production-platform-guide)、入口セキュリティは [Firewall・WAF・BotID](/blog/vercel-firewall-waf-botid-ddos-security-guide) を参照してください。

---

## 3つの環境を使い分ける

Vercel の環境変数は**環境ごとに値を変えられます**。値は**保存時に暗号化**され、プロジェクトにアクセスできるメンバーに見えます。

| 環境 | いつ適用されるか | 用途 |
|---|---|---|
| **Production** | 本番ブランチ（通常 `main`）へのプッシュ / `vercel --prod` | 本番のキー・接続文字列 |
| **Preview** | 本番以外のブランチへのプッシュ / `vercel` | ステージングDB等。**ブランチ別に上書き可** |
| **Development** | `vercel dev` / ローカル | ローカル開発用 |

```bash
# 環境ごとに値を登録
vercel env add DATABASE_URL production    # 本番DB
vercel env add DATABASE_URL preview       # ステージングDB
vercel env add DATABASE_URL development   # ローカルDB

# 特定ブランチだけ上書きしたいとき（preview）
# → ダッシュボードでブランチ指定。同名変数はブランチ別が優先される
```

> **重要な落とし穴**：**環境変数の変更は、新しいデプロイにのみ適用**されます。既存の本番デプロイは値が変わりません。「変えたのに反映されない」の大半はこれ——**再デプロイ**してください。

### Preview のブランチ別上書き

Preview 変数は「全非本番ブランチ」か「特定ブランチ」に適用できます。ブランチ指定の変数は同名の一般 Preview 変数を**上書き**するので、全部を複製せず**差分だけ**定義すれば済みます。

---

## NEXT_PUBLIC_ の罠（最重要）

最も多い、そして最も危険な事故が **`NEXT_PUBLIC_` 接頭辞**です。

- **`NEXT_PUBLIC_` を付けた変数は、ビルド時にバンドルへ埋め込まれ、ブラウザに露出**します。
- だから、**API キー・DB 接続文字列・秘密鍵・サービスロールキーには絶対に付けない**。
- 付けてよいのは「クライアントで読む必要がある**公開値**」だけ（公開可能な計測 ID、公開 API のベースURL など）。

```ts
// ❌ 絶対NG：秘密に NEXT_PUBLIC_ → ブラウザに丸見え
// NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_xxx

// ✅ サーバーでだけ読む（無印）
const stripeSecret = process.env.STRIPE_SECRET_KEY; // サーバー専用

// ✅ クライアントで読む公開値だけ NEXT_PUBLIC_
const ga = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID; // 公開してよい
```

> Supabase の `anon key` と `service_role key` の取り違え、`NEXT_PUBLIC_` への秘密混入は、実際の脆弱性診断で頻出します（[env リーク防止](/blog/nextjs-env-secret-leak-prevention-public-vars-guide)、[anon/service_role の露出](/blog/supabase-anon-key-service-role-key-exposure-guide)）。**「クライアントで読む必要が本当にあるか」を一段疑う**のが防御です。

---

## サイズ上限とランタイム差

- 合計 **64KB / デプロイ**（全変数の合計。単一変数も 64KB 以下）。JWT・証明書のような大きな値も扱えます。
- 対応ランタイム（64KB）：Node.js / Python / Ruby / Go / PHP コミュニティランタイム。
- **Edge ランタイムは 1変数 5KB まで**。Edge ミドルウェアで大きな値を読むなら注意。

---

## ローカル開発：vercel env pull

ローカルでは `.env.local`（または `vercel env pull` が生成する `.env`）に開発用変数を置きます。

```bash
# Development 環境の変数をローカルへ同期
vercel env pull .env.local

# vercel dev なら自動で Development 変数をメモリに読み込む（pull不要）
vercel dev
```

`.env*` は**コミットしない**（`.gitignore` に必ず入れる）。Vercel CLI 経由のデプロイは `.env` 系を自動で無視しますが、Git 経由は `.gitignore` が頼りです。

> **`@vercel/speed-insights` / `@vercel/analytics` の罠**：これらは**`package.json` の依存**に入れます。グローバルに入れて参照すると、特にモノレポでビルドエラーになります（[可観測性](/blog/vercel-observability-monitoring-speed-insights-log-drains-guide)）。

---

## システム環境変数

Vercel は実行時に有用なシステム変数を注入します。

| 変数 | 内容 |
|---|---|
| `VERCEL_ENV` | `production` / `preview` / `development` |
| `VERCEL_URL` | このデプロイの生成URL |
| `VERCEL_GIT_COMMIT_SHA` | デプロイ元のコミット |
| `VERCEL_REGION` | 実行リージョン |

```ts
// 環境で分岐（例：プレビューだけ noindex、本番だけ外部送信）
const isProd = process.env.VERCEL_ENV === "production";
if (!isProd) headers.set("X-Robots-Tag", "noindex");
```

---

## OIDC 鍵レス：外部クラウドへ長命キーを置かない

AWS S3・SES、GCP、データベースなど外部リソースへアクセスするとき、**長命のアクセスキーを環境変数に置く**のは2026年では非推奨です。**OIDC（OpenID Connect）連携で一時クレデンシャル**を得ます。

- Vercel の OIDC トークンを外部クラウドの IAM ロールが信頼し、**鍵を保管せずに**一時的な権限を得る。
- 漏洩リスクが構造的に下がり、ローテーション運用も消える。
- CI/CD（GitHub Actions → Vercel/AWS）も同じく OIDC 鍵レスに（[OIDC 鍵レス CI/CD](/blog/github-actions-oidc-keyless-cicd-aws-gcp-guide)）。

どうしても長命キーが必要な場合は、**最小権限**に絞り、Production にのみ置き、定期ローテーションします。

---

## Fluid Compute での秘密の扱い

[Fluid Compute](/blog/vercel-functions-fluid-compute-streaming-cron-guide) は1インスタンスで複数リクエストを並行処理します。

```ts
// ✅ 起動時に一度だけ読む（リクエスト非依存）
const apiKey = process.env.EXTERNAL_API_KEY!;

// ❌ リクエスト固有のトークンをモジュールスコープにキャッシュしない
// let userToken; // 別リクエストに漏れる
```

リクエストごとのトークン・ユーザー秘密は**関数スコープのローカル**に閉じます。

---

## 型安全な env 境界（Zod）

環境変数は「外部入力」です。**起動時に Zod で検証**して、未設定や形式不正をビルド/起動で落とします。これで「本番で env 未設定の 500」を未然に防げます。

```ts
// lib/env.ts — env を型安全な単一の真実源に
import { z } from "zod";

const schema = z.object({
  DATABASE_URL: z.string().url(),
  STRIPE_SECRET_KEY: z.string().startsWith("sk_"),
  NEXT_PUBLIC_GA_MEASUREMENT_ID: z.string().optional(),
});

// 起動時に検証（失敗したら即座に落ちる＝本番で気づくより安全）
export const env = schema.parse(process.env);
```

`process.env.X` を直に散らさず、`env.X` 経由にすることで、**型・必須・形式**が一箇所で保証されます（[型安全の徹底](/blog/typescript-type-safety-discipline-zod-nevererror-no-any)）。

---

## 本番チェックリスト（env・シークレット）

- [ ] 3環境（production/preview/development）に**値を整理**
- [ ] **`NEXT_PUBLIC_` に機密を付けていない**（ブラウザ露出）
- [ ] 変更後は**再デプロイ**（既存デプロイには反映されない）
- [ ] `.env*` をコミットしていない
- [ ] Edge で読む変数は **5KB 以内**、合計 64KB 以内
- [ ] 外部クラウドは **OIDC 鍵レス**、長命キーは最小権限＋ローテーション
- [ ] Fluid のグローバルに**リクエスト固有の秘密を残さない**
- [ ] env を **Zod で起動時検証**（型安全な境界）

---

## まとめ

シークレット管理は「派手さはないが、外すと一発」の領域です。

1. **3環境**を使い分け、変更は**再デプロイ**で反映
2. **`NEXT_PUBLIC_` に秘密を付けない**（最重要）
3. ローカルは **`vercel env pull`**、`.env` はコミットしない
4. 外部クラウドは **OIDC 鍵レス**で長命キーを消す
5. env は **Zod で型安全な境界**にする

シークレット管理の監査・OIDC 鍵レス化・型安全な env 境界の導入を、案件として承ります。

> 本記事は [Vercel 環境変数](https://vercel.com/docs/environment-variables) 公式ドキュメント（2026年6月時点）に基づきます。上限・仕様は更新されるため、本番採用時は公式で最新値を確認してください。
