Next.js で環境変数 (process.env) が読み込めない
Next.js の環境変数はビルド時にインライン化される。
ブラウザに露出する値は NEXT_PUBLIC_ プレフィックスが必須で、.env ファイルの優先順位とビルドの再実行も意識する必要がある。
公開: 更新:
要約
Next.js の環境変数はサーバ側とブラウザ側で扱いが違う。
ブラウザに渡したい値は NEXT_PUBLIC_ プレフィックス必須で、付け忘れると process.env.FOO は undefined になる。
.env.local を変更した後は dev サーバの再起動が必要、本番ビルド時はビルド実行シェルに値があることを確認する。
仕様は Environment Variables(新しいタブで開く) に明記されている。
実行例
node:20 で Next.js の本番ビルドを繰り返すと、プレフィックスの無い API_URL は .next/static から見つからず、NEXT_PUBLIC_API_URL に改めた時点でクライアント JS に URL が埋め込まれ、.env.production に別の URL を足しても採用されたのは .env.local 側の値だった。
値を持たずにビルドした成果物は next start に値を渡しても API: undefined のままで、ビルドするシェルで export し直してから作り直すと API: https://api.example.com が返っている。
$ npm run build > build.log 2>&1
$ echo $?
0$ grep -E "Environments|Compiled successfully" build.log
- Environments: .env.local
✓ Compiled successfully in 1966ms$ grep -rl https://api.example.com .next/static
$ echo $?
1$ cat .env.local
DATABASE_URL=postgres://db.internal:5432/app
NEXT_PUBLIC_API_URL=https://api.example.com$ npm run build > build.log 2>&1
$ echo $?
0$ grep -E "Environments|Compiled successfully" build.log
- Environments: .env.local
✓ Compiled successfully in 2.0s$ grep -rhoE 'https://api[.a-z]*example.com' .next/static | sort -u
https://api.example.com$ cat .env.production
NEXT_PUBLIC_API_URL=https://api.production.example.com$ npm run build > build.log 2>&1
$ echo $?
0$ grep -E "Environments|Compiled successfully" build.log
- Environments: .env.local, .env.production
✓ Compiled successfully in 1960ms$ grep -rhoE 'https://api[.a-z]*example.com' .next/static | sort -u
https://api.example.com$ npm run build > build.log 2>&1
$ echo $?
0$ grep -E "Environments|Compiled successfully" build.log
✓ Compiled successfully in 1943ms$ NEXT_PUBLIC_API_URL=https://api.example.com npm run start -- -p 3000 > start.log 2>&1 &$ curl -s http://localhost:3000/ | grep -o 'API: [^<]*'
API: undefined$ export NEXT_PUBLIC_API_URL=https://api.example.com$ npm run build > build.log 2>&1
$ echo $?
0$ grep -E "Environments|Compiled successfully" build.log
✓ Compiled successfully in 1956ms$ npm run start -- -p 3001 > start.log 2>&1 &$ curl -s http://localhost:3001/ | grep -o 'API: [^<]*'
API: https://api.example.com— 2026-09-27 時点の出力
検証環境
- 検証日
- 実行環境
node:20Debian GNU/Linux 12 (bookworm)- バージョン
- Node.js 20.20.2
- npm 10.8.2
- Python 3.11.2
- Git 2.39.5
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- NEXT_PUBLIC_ 付け忘れ: ブラウザに露出させる値は明示的に
NEXT_PUBLIC_を付ける必要がある。
付けない値はクライアント側でundefined - dev サーバ未再起動:
.env*ファイルはプロセス起動時に読み込まれる。
編集後は Ctrl+C で停止して再起動しないと反映されない - ビルド時に未定義:
next buildの時点で値が無いと、その値はundefinedとしてバンドルされ、実行時の env を変えても上書きされない - ファイル優先順位の誤解:
.env.production.local>.env.local>.env.production>.envの順で読まれる。
上位ファイルで意図せず空文字を入れていないか確認
解決策
1. NEXT_PUBLIC_ プレフィックスを付ける
# .env.local
DATABASE_URL=postgres://... # サーバ専用
NEXT_PUBLIC_API_URL=https://api.example.com # クライアントから参照可// app/page.tsx (Server Component なら両方読める)
console.log(process.env.DATABASE_URL);
// app/components/Client.tsx ("use client")
console.log(process.env.NEXT_PUBLIC_API_URL); // OK
console.log(process.env.DATABASE_URL); // undefined2. dev サーバを再起動
# Ctrl+C で止めて
npm run devホットリロードは .env* の変更を検出しない。
3. 本番ビルドのシェルで export
export NEXT_PUBLIC_API_URL=https://api.example.com
export DATABASE_URL=postgres://...
npm run buildCI ではビルドステップの環境に値を渡す。Vercel / Cloud Run / Amplify などは UI で設定する。
4. ファイル優先順位を確認
.env.development.local ← dev 時のローカル上書き(git ignore 推奨)
.env.local ← 全環境のローカル上書き(git ignore 推奨)
.env.development ← dev のデフォルト
.env ← ベース複数ファイルがある場合、上のファイルの値が下を上書きする。
環境別のデフォルト(.env.development / .env.production)よりも .env.local のほうが強い。
ただし NODE_ENV が test のときだけは .env.local が読まれない。
空文字を書くと「未設定」ではなく「空文字」になるので注意。