環境変数はいつ読まれるのか。ビルド時と実行時
Next.js の環境変数は、ページがいつ描かれるかで、ビルド時に読まれるか実行時に読まれるかが決まります。
読まれるのは「描いたとき」
process.env を読む行は、そのページを描いたときに動きます。だから、いつ描かれるページなのかで、読まれる値が変わります。
| どこで読むか | 読まれるとき |
|---|---|
| 事前に描くページ(一覧で ○)の Server Component | ビルド時 |
| 開かれたときに描くページ(一覧で ƒ)の Server Component | 開かれたとき |
| NEXT_PUBLIC_ の付いた変数 | ビルド時(JavaScript に埋め込まれる) |
Cookie もクエリ文字列も使っていないページは、ビルド時に描かれます(キャッシュの解説)。そのページの中の process.env も、ビルド時に読まれて結果が HTML に焼き付きます。
実行時に値を変えても変わらない
同じものをビルドして、実行するときに別の値を渡しました。
.env(ビルド時) API_BASE=build-time-value NEXT_PUBLIC_LABEL=build-label
実行時に渡した値 API_BASE=runtime-value NEXT_PUBLIC_LABEL=runtime-label
| 表示された値 | |
|---|---|
| 事前に描くページ | build-time-value |
| 開かれたときに描くページ | runtime-value |
| NEXT_PUBLIC_LABEL | build-label |
実行時の値を読んだのは、開かれたときに描くページだけでした。ほかの2つは、ビルド時の値のまま動かしようがありません。
なお、開かれたときに描くページでは、実行時に渡した値が .env の値より優先されました。公式ドキュメントの読み込み順でも、process.env がいちばん先です。
Docker で undefined になる
いちばん踏みやすいのがこの形です。
- ビルドのとき(
docker build)には値を渡さない - 実行するとき(
docker run -eや compose のenvironment)にだけ渡す
| 表示された値 | |
|---|---|
| 事前に描くページ | undefined |
| 開かれたときに描くページ | 実行時の値 |
| NEXT_PUBLIC_ の付いた変数 | undefined |
Docker で置くときの全体の手順(standalone で写すもの、HOSTNAME)は自分のサーバーに置くにまとめています。
直し方
値の使い道で分けます。
ブラウザで使う値(NEXT_PUBLIC_)
ビルドのときに渡します。ビルド時に JavaScript へ埋め込まれるので、実行時に渡しても届きません。
公式ドキュメントも、1つのイメージを複数の環境で使い回すと、NEXT_PUBLIC_ の値はビルド時の値で固まると書いています。環境ごとに値が違うなら、環境ごとにビルドします。
サーバーだけで使う値
そのページを開かれたときに描く形にします。connection() を先頭で待つと、そのページはビルド時に描かれなくなります。
import { connection } from 'next/server'
export default async function Page() {
await connection()
return <p>{`api=${process.env.API_BASE}`}</p>
}
実機で、この形なら一覧が ƒ になり、実行時に渡した値が出ることを確かめました。公式ドキュメントも、実行時の値を読む方法としてこの形を示しています。
NEXT_PUBLIC_ を付けずに Client Component で読むと
NEXT_PUBLIC_ の無い変数は、ブラウザ向けの JavaScript には入りません。ただし Client Component も初回の表示のためにサーバーで一度描かれるので、そのときには値が読めてしまいます。
実機では、事前に描いた HTML に値がそのまま入り、ブラウザ側では undefined になって表示が食い違いました(hydration のエラー。Hydration failed の直し方)。
秘密の値を Client Component で読まないでください。読んでいいのは、ブラウザに見えて困らない値だけで、それには NEXT_PUBLIC_ を付けます(server-only の解説)。
確かめ方
pnpm buildの一覧で、そのページが○かƒかを見る。○ならビルド時に読まれている- 本番と同じ手順でビルドしたもので、値が入っているかを見る。開発サーバーでは確かめられない
NEXT_PUBLIC_の値を変えたら、ビルドし直す
出典
- nextjs.org/docs/app/guides/environment-variables
- nextjs.org/docs/app/api-reference/functions/connection
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。