🐤

NEXT_PUBLIC_環境変数はサーバーサイドから読み取れない

に公開

公式ドキュメントに書いてあることなのですが、ちょっとハマったので共有です。
(元記事はdev.toに投稿したこちらの記事です)

tl;dr

サーバーサイドで使用する環境変数にはNEXT_PUBLICのプレフィックスを付けないこと。

起こったこと

自分のNext.jsプロジェクトで以下のような環境変数を定義していました。

NEXT_PUBLIC_API_BASE_URL=https://(略)/api

APIエンドポイントのベースURLです。
これを以下のように使用していました(実際のコードを簡易化したものですが、やっていることは同じです)。

// In src/utils/env.ts
// 環境変数を返す関数を定義し、アプリケーション内ではその関数を通して環境変数を使用する
export const getApiBaseUrl = (): string => {
  if (!process.env.NEXT_PUBLIC_API_BASE_URL) {
    throw new Error("NEXT_PUBLIC_API_BASE_URL is undefined");
  }

  return process.env.NEXT_PUBLIC_API_BASE_URL;
};

そして以下のような関数をサーバーサイドで使用していました。

// API call 関数
// サーバーコンポーネントやサーバーアクションなどサーバーサイドで呼ばれる
export const getEventByUuidService = async (uuid: string): Promise<Event> => {
  try {
    const res = await fetch(`${getApiBaseUrl()}/event/${uuid}`, { cache: "no-store" });

    if (!res.ok) {
      throw new Error("Failed to get event by uuid");
    }

    return (await res.json()).data;
  } catch (error) {
    throw error;
  }
};

ローカルで開発中には何のエラーも出なかったのですが、いざVercelにデプロイするとこのようなエラーログが出ていました。

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:11730:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause: Error: connect ECONNREFUSED 127.0.0.1:3000
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16)
      at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:128:17) {
    errno: -111,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 3000
  }
}

さらにChromeのネットワークタブを確認すると、/api/events/{uuid}に行くはずのリクエストが代わりに/eventsに送られているのが分かりました。つまりNEXT_PUBLIC_API_BASE_URLが無視されていました。

解決方法

公式ドキュメントのこの部分にこのような記載がありました。

To expose an environment variable to the browser, it must be prefixed with NEXT_PUBLIC_. However, these public environment variables will be inlined into the JavaScript bundle during next build.

クライアント側のJSに組み込まれてしまう、つまりサーバーサイドでは読み取れないということです。
なので解決策は単純にNEXT_PUBLICのプレフィックスを付けなければいいという、ただそれだけの話でした(実際にNEXT_PUBLICのプレフィックスを削除すると正常に動作しました)。

結論

クライアント側でアクセスする必要がある環境変数にのみNEXT_PUBLICプレフィックスをつける。

Discussion