Gojabako ZoneKei Ito

Cloud Run, Amplify, Netlify, Vercel上のNext.js環境変数事情

に公開に更新)履歴 (8)

前の記事で環境を複数にしたのでログをNewRelicに集めようとしたら環境変数が素直に渡らないことがあったので実験しました。

## 検証したいこと

以下の2点です。

  1. .envファイルnext.config.js、Vercel等の設定画面の設定値はどれが勝つのか?
  2. middleware、サーバー、クライアントでどの環境変数が使えるのか?

## 検証方法

以下のラインナップで環境変数を設定します。説明のためVercelを例にします。

#table1
環境変数 ※1観点
EVTEST_ENVEどこで使えるか
EVTEST_CNFCどこで使えるか
EVTEST_HSTHどこで使えるか
EVTEST_ENV_CNFECどちらの値が見えるのか
EVTEST_ENV_HSTEHどちらの値が見えるのか
EVTEST_CNF_HSTCHどちらの値が見えるのか

※1 NEXT_PUBLIC_EVTEST_ENV のように NEXT_PUBLIC_ をつけたものも用意します。

値の設定方法

### .envファイルでの設定

#code1
1EVTEST_ENV=E2EVTEST_ENV_CNF=E3EVTEST_ENV_HST=E4NEXT_PUBLIC_EVTEST_ENV=E5NEXT_PUBLIC_EVTEST_ENV_CNF=E6NEXT_PUBLIC_EVTEST_ENV_HST=E

### next.config.js (next.config.ts) での設定

#code2
1const nextConfig: NextConfig = {2 env: {3 EVTEST_CNF: "C",4 EVTEST_ENV_CNF: "C",5 EVTEST_CNF_HST: "C",6 NEXT_PUBLIC_EVTEST_CNF: "C",7 NEXT_PUBLIC_EVTEST_ENV_CNF: "C",8 NEXT_PUBLIC_EVTEST_CNF_HST: "C",9 // 以下はここで中継してみるテストです。10 EVTEST_ENV2: process.env.EVTEST_ENV,11 EVTEST_CNF2: process.env.EVTEST_CNF,12 EVTEST_HST2: process.env.EVTEST_HST,13 EVTEST_ENV_CNF2: process.env.EVTEST_ENV_CNF,14 EVTEST_ENV_HST2: process.env.EVTEST_ENV_HST,15 EVTEST_CNF_HST2: process.env.EVTEST_CNF_HST,16 NEXT_PUBLIC_EVTEST_ENV2: process.env.NEXT_PUBLIC_EVTEST_ENV,17 NEXT_PUBLIC_EVTEST_CNF2: process.env.NEXT_PUBLIC_EVTEST_CNF,18 NEXT_PUBLIC_EVTEST_HST2: process.env.NEXT_PUBLIC_EVTEST_HST,19 NEXT_PUBLIC_EVTEST_ENV_CNF2: process.env.NEXT_PUBLIC_EVTEST_ENV_CNF,20 NEXT_PUBLIC_EVTEST_ENV_HST2: process.env.NEXT_PUBLIC_EVTEST_ENV_HST,21 NEXT_PUBLIC_EVTEST_CNF_HST2: process.env.NEXT_PUBLIC_EVTEST_CNF_HST,22 },23};

### Vercelの設定画面での設定

Vercelの環境変数設定画面#img1
Vercelの環境変数設定画面

### Cloud Runの設定画面での設定

Cloud Runの環境変数設定画面#img2
Cloud Runの環境変数設定画面

### Amplifyの設定画面での設定

Amplifyの環境変数設定画面#img3
Amplifyの環境変数設定画面

### Netlifyの設定画面での設定

Netlifyの環境変数設定画面 (値が見えないですがHに設定しています。)#img4
Netlifyの環境変数設定画面 (値が見えないですがHに設定しています。)

(Xenv,Xconf,Xhost) の設定に対して、以下のタイミングで値を確認します。

値の確認方法

まず以下の関数を用意しました。

環境変数を列挙する関数 listEnvTestEntries#code3
1export const listEnvTestEntries = function* (): Generator<[string, string | undefined]> {2 yield ["EVTEST_ENV", process.env.EVTEST_ENV];3 yield ["EVTEST_CNF", process.env.EVTEST_CNF];4 yield ["EVTEST_HST", process.env.EVTEST_HST];5 yield ["EVTEST_ENV_CNF", process.env.EVTEST_ENV_CNF];6 yield ["EVTEST_ENV_HST", process.env.EVTEST_ENV_HST];7 yield ["EVTEST_CNF_HST", process.env.EVTEST_CNF_HST];8 yield ["NEXT_PUBLIC_EVTEST_ENV", process.env.NEXT_PUBLIC_EVTEST_ENV];9 yield ["NEXT_PUBLIC_EVTEST_CNF", process.env.NEXT_PUBLIC_EVTEST_CNF];10 yield ["NEXT_PUBLIC_EVTEST_HST", process.env.NEXT_PUBLIC_EVTEST_HST];11 yield ["NEXT_PUBLIC_EVTEST_ENV_CNF", process.env.NEXT_PUBLIC_EVTEST_ENV_CNF];12 yield ["NEXT_PUBLIC_EVTEST_ENV_HST", process.env.NEXT_PUBLIC_EVTEST_ENV_HST];13 yield ["NEXT_PUBLIC_EVTEST_CNF_HST", process.env.NEXT_PUBLIC_EVTEST_CNF_HST];14 yield ["EVTEST_ENV2", process.env.EVTEST_ENV2];15 yield ["EVTEST_CNF2", process.env.EVTEST_CNF2];16 yield ["EVTEST_HST2", process.env.EVTEST_HST2];17 yield ["EVTEST_ENV_CNF2", process.env.EVTEST_ENV_CNF2];18 yield ["EVTEST_ENV_HST2", process.env.EVTEST_ENV_HST2];19 yield ["EVTEST_CNF_HST2", process.env.EVTEST_CNF_HST2];20 yield ["NEXT_PUBLIC_EVTEST_ENV2", process.env.NEXT_PUBLIC_EVTEST_ENV2];21 yield ["NEXT_PUBLIC_EVTEST_CNF2", process.env.NEXT_PUBLIC_EVTEST_CNF2];22 yield ["NEXT_PUBLIC_EVTEST_HST2", process.env.NEXT_PUBLIC_EVTEST_HST2];23 yield ["NEXT_PUBLIC_EVTEST_ENV_CNF2", process.env.NEXT_PUBLIC_EVTEST_ENV_CNF2];24 yield ["NEXT_PUBLIC_EVTEST_ENV_HST2", process.env.NEXT_PUBLIC_EVTEST_ENV_HST2];25 yield ["NEXT_PUBLIC_EVTEST_CNF_HST2", process.env.NEXT_PUBLIC_EVTEST_CNF_HST2];26};

### Middleware処理時

middleware.tsで /envtest へのリクエストに上記関数の結果を返すようにします。このページでの結果は以下の通りです。

### このページのSSR処理時

SSRなコンポーネントで上記関数の結果を返すようにします。

EnvTestSsr.tsx#code4
1import { listEnvTestEntries } from "./path/to/listEnvTestEntries";2import { EnvTestData } from "./EnvTestData";3export const EnvTestSsr = () => (4 <EnvTestData data={[...listEnvTestEntries()]} columnName="SSR" />5);

EnvTestDataEVTEST_ENV=envのように変数名とその値を1行ずつ出力します。このページでの結果は以下の通りです。

EVTEST_ENV=E
EVTEST_CNF=C
EVTEST_HST=
EVTEST_ENV_CNF=C
EVTEST_ENV_HST=E
EVTEST_CNF_HST=C
NEXT_PUBLIC_EVTEST_ENV=E
NEXT_PUBLIC_EVTEST_CNF=C
NEXT_PUBLIC_EVTEST_HST=
NEXT_PUBLIC_EVTEST_ENV_CNF=C
NEXT_PUBLIC_EVTEST_ENV_HST=E
NEXT_PUBLIC_EVTEST_CNF_HST=C
EVTEST_ENV2=E
EVTEST_CNF2=
EVTEST_HST2=
EVTEST_ENV_CNF2=E
EVTEST_ENV_HST2=E
EVTEST_CNF_HST2=
NEXT_PUBLIC_EVTEST_ENV2=E
NEXT_PUBLIC_EVTEST_CNF2=
NEXT_PUBLIC_EVTEST_HST2=
NEXT_PUBLIC_EVTEST_ENV_CNF2=E
NEXT_PUBLIC_EVTEST_ENV_HST2=E
NEXT_PUBLIC_EVTEST_CNF_HST2=

### /2024/nextjs-env/api/route.ts の処理時

SSRと同じ結果と予想したのですが、念のため用意しました。

route.ts#code5
1import { NextResponse } from "next/server";2import { listEnvTestEntries } from "./path/to/listEnvTestEntries";3export const GET = () => NextResponse.json([...listEnvTestEntries()]);

このページでの結果は以下の通りです。

### このページのクライアント処理時

EnvTestSsr.tsx を "use client" にしたものです。Hydrationを避けるためuseEffect内で値を取得しています。

EnvTestClient.tsx#code6
1"use client";2import { useEffect, useState } from "react";3import { listEnvTestEntries } from "./path/to/listEnvTestEntries";4import { EnvTestData } from "./EnvTestData";5export const EnvTestClient = () => {6 const [data, setData] = useState<Array<[string, string | undefined]>>([]);7 useEffect(() => setData([...listEnvTestEntries()]), []);8 return <EnvTestData data={data} columnName="Client" />;9};

このページでの結果は以下の通りです。

## 2024年12月15日の結果

publicNEXT_PUBLIC_ をつけた場合です。後半は next.config.js で中継した場合です。

Xenv
Xconf
Xhost
Ymid
Yssr
Yroute
Yclient
#table-summary
環境変数の設定
Xenv
Xconf
Xhost
1.removeEremoveremove
2.removeremoveCremove
3.removeremoveremoveH
4.removeECremove
5.removeEremoveH
6.removeremoveCH
7.publicEremoveremove
8.publicremoveCremove
9.publicremoveremoveH
10.publicECremove
11.publicEremoveH
12.publicremoveCH
13.removeEremoveremove
14.removeremoveCremove
15.removeremoveremoveH
16.removeECremove
17.removeEremoveH
18.removeremoveCH
19.publicEremoveremove
20.publicremoveCremove
21.publicremoveremoveH
22.publicECremove
23.publicEremoveH
24.publicremoveCH
Ymiddle
E
C
H
C
H
C
E
C
H
C
E
C
E
E
E
E
E
E
Yserver
E
C
C
E
C
E
C
C
E
C
E
E
E
E
E
E
Yroute
E
C
H
C
H
C
E
C
H
C
E
C
E
E
E
E
E
E
Yclient
C
C
C
E
C
C
E
C
E
E
E
E
E
E
Cloud Run
Ymiddle
E
C
C
E
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yserver
E
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yroute
E
C
C
E
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yclient
C
C
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Amplify
Ymiddle
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yserver
E
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yroute
E
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yclient
C
C
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Netlify
Ymiddle
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yserver
E
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yroute
E
C
H
C
H
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Yclient
C
C
C
E
C
H
C
H
C
E
H
E
H
H
E
H
E
H
H
Vercel
  1. .envで設定した環境変数はどこで使えるのか (1, 7, 13, 19行目)
    1. サーバーで使える。NEXT_PUBLIC_ がついていればクライアントでも使える。
    2. Cloud RunとAmplifyではMiddlewareでも使える。
    3. VercelとNetlifyのMiddlewareでは使えない。NEXT_PUBLIC_ がついていれば使える。
  2. next.config.jsで設定した環境変数はどこで使えるのか (2, 8, 14, 20行目)
    1. どこでも使える。NEXT_PUBLIC_ がついていなくてもクライアントで使える。
  3. Cloud Runで設定した環境変数はどこで使えるのか (3, 9行目)
    1. middlewareとrouteで使える。NEXT_PUBLIC_ がついていてもクライアントでは使えない。
  4. Amplifyで設定した環境変数はどこで使えるのか (3, 9行目)
    1. SSR時に使える。NEXT_PUBLIC_ がついていれば使える。
    2. next.config.jsで中継するとどこでも使える。
  5. Netlify, Vercelで設定した環境変数はどこで使えるのか (3, 9行目)
    1. クライアント以外で使える。NEXT_PUBLIC_ がついていればクライアントでも使える。
  6. XenvXconfXhostの環境設定変数の優先順位
    1. (Xenv,Xconf)Xconf が勝つ。(4行目)
    2. (Xenv,Xhost) は ... 5行目を見てください。
    3. (Xconf,Xhost)Xconf が勝つ。(6行目)
  7. next.config.js で中継するとどうなるか (13-24行目)
    1. Cloud Runでは.envにある値以外は中継されず、既存の値も隠れてしまう。中継しない方がいい。
    2. Amplify, Netlify, Vercelでは中継される。クライアントでも使える。

## このページでの結果まとめ

#envtest-result
環境変数
Ymiddle
Yserver
Yroute
Yclient
1
EVTEST_ENV
2
EVTEST_CNF
3
EVTEST_HST
4
EVTEST_ENV_CNF
5
EVTEST_ENV_HST
6
EVTEST_CNF_HST
7
NEXT_PUBLIC_EVTEST_ENV
8
NEXT_PUBLIC_EVTEST_CNF
9
NEXT_PUBLIC_EVTEST_HST
10
NEXT_PUBLIC_EVTEST_ENV_CNF
11
NEXT_PUBLIC_EVTEST_ENV_HST
12
NEXT_PUBLIC_EVTEST_CNF_HST
13
EVTEST_ENV2
14
EVTEST_CNF2
15
EVTEST_HST2
16
EVTEST_ENV_CNF2
17
EVTEST_ENV_HST2
18
EVTEST_CNF_HST2
19
NEXT_PUBLIC_EVTEST_ENV2
20
NEXT_PUBLIC_EVTEST_CNF2
21
NEXT_PUBLIC_EVTEST_HST2
22
NEXT_PUBLIC_EVTEST_ENV_CNF2
23
NEXT_PUBLIC_EVTEST_ENV_HST2
24
NEXT_PUBLIC_EVTEST_CNF_HST2
JSON
{
  "Ymiddle": ",,,,,,,,,,,,,,,,,,,,,,,",
  "Yserver": ",,,,,,,,,,,,,,,,,,,,,,,",
  "Yroute": ",,,,,,,,,,,,,,,,,,,,,,,",
  "Yclient": ",,,,,,,,,,,,,,,,,,,,,,,"
}

以上です。MiddlewareからOpenTelemetryでログを送るところはまた別の記事で書きます。