← 記事一覧に戻る

Vercel で環境変数が undefined になる・本番に反映されない時の5つの原因と対策【NEXT_PUBLIC_ / Redeploy / スコープ】

Vercel にデプロイしたら環境変数が undefined になった

ローカルでは ({}).NEXT_PUBLIC_API_URL が正しく取得できているのに、Vercel にデプロイすると undefined になる——このトラブルは Next.js + Vercel の組み合わせで非常によく起きます。

原因は複数あり、それぞれ対処法が異なります。この記事では実務でよく遭遇するパターンを5つに分類して解説します。

原因1: クライアントサイドで NEXT_PUBLIC_ プレフィックスが付いていない

最も多いケースです。

Next.js では、ブラウザ(クライアントサイド)から参照できる環境変数には NEXT_PUBLIC_ プレフィックスが必須 です。このプレフィックスがないと、サーバーサイドでは読めてもクライアントサイドでは undefined になります。

# Vercel の環境変数設定(NG)
API_URL=https://api.example.com

# Vercel の環境変数設定(OK — クライアントから参照する場合)
NEXT_PUBLIC_API_URL=https://api.example.com
// クライアントコンポーネントでの参照
'use client'

export default function ApiStatus() {
  // NEXT_PUBLIC_ なし → undefined になる
  const bad = ({}).API_URL

  // NEXT_PUBLIC_ あり → 正しく取得できる
  const good = ({}).NEXT_PUBLIC_API_URL

  return <p>{good}</p>
}

NEXT_PUBLIC_ を付けた環境変数はビルド時にバンドルへインライン展開されます。そのため ビルド後に値を変えてもリデプロイが必要(後述)です。

また、シークレットキーやAPIの秘密鍵など、クライアントに漏れてはいけない値には NEXT_PUBLIC_ を絶対に付けないでください。

原因2: 環境変数を追加・変更した後にリデプロイしていない

Vercel のダッシュボードで環境変数を追加しても、既存のデプロイには反映されません。 環境変数はビルド時に焼き込まれるため、設定変更後は必ず再デプロイが必要です。

確認手順:

  1. Vercel ダッシュボード → プロジェクト → Settings → Environment Variables で変数を追加・更新
  2. Deployments タブを開き、最新デプロイの「⋯」メニューから Redeploy をクリック
  3. “Use existing Build Cache” のチェックを外してリデプロイ(キャッシュが残ると古い値が使われる場合がある)
# Vercel CLI を使う場合
vercel --prod

特に NEXT_PUBLIC_ 付きの変数は変更のたびにリデプロイが必要な点を覚えておきましょう。

原因3: .env.local をコミットしていない / Vercel に設定していない

ローカル開発では .env.local に書いた環境変数が自動で読み込まれますが、このファイルは .gitignore に含まれているため Git にはコミットされません。 Vercel はあくまでリポジトリからビルドするので、.env.local の内容は Vercel 側には存在しません。

ローカルでは動くのに本番で undefined になる場合の典型パターンです。

対処法: Vercel ダッシュボードの Environment Variables に、.env.local に書いている値を手動で登録します。

# .env.local(ローカルのみ、Git管理外)
NEXT_PUBLIC_API_URL=http://localhost:3001
DATABASE_URL=postgres://localhost:5432/mydb

# → Vercel の Environment Variables に同じキーと本番用の値を登録する

Vercel CLI を使えば .env ファイルから一括インポートも可能です:

vercel env pull .env.local
# または逆方向(ローカル → Vercel)はダッシュボードから手動登録

原因4: 環境変数のスコープが Production に設定されていない

Vercel の環境変数には Production / Preview / Development の3つのスコープがあります。デフォルトで全てにチェックが入っていることが多いですが、誤って Production だけ外れていると本番デプロイで undefined になります。

Vercel Dashboard → Settings → Environment Variables

┌──────────────────┬────────────┬─────────┬─────────────┐
│ Variable Name    │ Production │ Preview │ Development │
├──────────────────┼────────────┼─────────┼─────────────┤
│ NEXT_PUBLIC_API  │ ✅ 有効    │ ✅ 有効 │ ✅ 有効     │
│ DATABASE_URL     │ ✅ 有効    │ ✅ 有効 │ ✅ 有効     │
└──────────────────┴────────────┴─────────┴─────────────┘

また、ブランチ別に異なる値を設定したい場合は、スコープを Preview にして特定ブランチを指定できます。本番(main ブランチ)にのみ適用したい変数は Production スコープだけを有効にします。

設定を変更したら忘れずにリデプロイしてください。

原因5: App Router でサーバーコンポーネントとクライアントコンポーネントを混同している

Next.js 13以降の App Router では、サーバーコンポーネントとクライアントコンポーネントで環境変数の挙動が異なります。

// サーバーコンポーネント(NEXT_PUBLIC_ なしでも読める)
// app/page.tsx
export default async function Page() {
  const secret = ({}).SECRET_KEY  // サーバーサイドのみ → OK
  const pub = ({}).NEXT_PUBLIC_API_URL  // どちらでも → OK
  return <div>{pub}</div>
}
// クライアントコンポーネント(NEXT_PUBLIC_ がないと undefined)
'use client'

export default function ClientComponent() {
  const secret = ({}).SECRET_KEY  // ❌ undefined になる
  const pub = ({}).NEXT_PUBLIC_API_URL  // ✅ 読める
  return <div>{pub}</div>
}

クライアントコンポーネントで NEXT_PUBLIC_ なしの変数を読もうとしても undefined になります。サーバーコンポーネントから props で渡すか、NEXT_PUBLIC_ を付けて公開変数として扱う必要があります。

// サーバーコンポーネントから props で渡す(推奨パターン)
// app/page.tsx(サーバーコンポーネント)
import ClientComponent from './ClientComponent'

export default function Page() {
  const apiEndpoint = ({}).API_ENDPOINT  // サーバーで読む
  return <ClientComponent apiEndpoint={apiEndpoint ?? ''} />
}

デバッグ方法:どの環境変数が読めているか確認する

問題の切り分けには、一時的に API ルートで環境変数を出力するのが手早い方法です:

// app/api/debug-env/route.ts(デバッグ用、本番運用では削除すること)
export async function GET() {
  return Response.json({
    NEXT_PUBLIC_API_URL: ({}).NEXT_PUBLIC_API_URL ?? 'undefined',
    NODE_ENV: "production",
    // SECRET_KEY などはここに含めないこと!
  })
}

また、Vercel CLI の vercel env ls コマンドで登録済みの環境変数一覧を確認できます:

vercel env ls

まとめ

症状 原因 対処法
クライアントで undefined NEXT_PUBLIC_ プレフィックスなし キー名に NEXT_PUBLIC_ を付けてリデプロイ
設定したのに反映されない リデプロイ忘れ Build Cache なしでリデプロイ
ローカルは動くが本番で undefined .env.local が Vercel に未登録 Vercel ダッシュボードに手動登録
Production のみ undefined スコープが Production 未選択 Environment Variables のスコープを確認
App Router で undefined クライアントコンポーネントでシークレット参照 props で渡すか NEXT_PUBLIC_ を使う

Next.js + Vercel の環境変数は「どこで読むか(サーバー/クライアント)」と「いつ焼き込まれるか(ビルド時/ランタイム)」の2軸を意識すると問題の原因を特定しやすくなります。まずは上記のチェックリストを順番に確認してみてください。