Next.jsの環境変数を理解するための徹底解説
はじめに
Next.jsのプロジェクトで環境変数を扱う際に、どのように設定すればいいのか悩んだ方は多いかもしれません。 とはいえ、実務のなかではAPIキーや接続先URL、動作モードの切り替えなど、環境変数を使う場面が少なくありません。 設定ミスによって機密情報が外部に漏れたり、動作が変わらないままデプロイしてしまったりする事例も見かけます。 そのため、環境変数の正しい使い方を理解しておくことは大切ではないでしょうか。
ここでは、Next.jsの最新バージョンを前提に、環境変数の設定方法や運用上のポイントを具体的に解説します。 初心者の皆さんでもイメージしやすいように、実際のプロジェクトで使われるシーンを踏まえながら説明していきます。
Next.jsにおける環境変数の概要
Next.jsでは、主にサーバーサイドでのみ有効になる変数と、クライアントサイドへも公開される変数の2つに分けることができます。 サーバーサイド向けの環境変数はプロジェクト内で安全に扱うことができますが、クライアント側のJavaScriptにも埋め込まれる形で露出する場合は、情報の公開範囲に注意が必要です。
例えば、サーバーサイドでのAPI認証に利用する秘密鍵やデータベース接続情報は、クライアント側に漏れないようにする必要があります。 逆に、クライアント側から直接呼び出すAPIのエンドポイントなどは、ユーザーに公開されても問題ない情報として取り扱うことが多いです。
このように、環境変数はセキュリティと直結するため、実務ではどの変数をどちらの領域で扱うのかを慎重に決める必要があります。
環境変数の設定ファイルと基本的な利用
Next.jsでは、.env
ファイルや.env.local
ファイルなどを用いて環境変数を管理するのが一般的です。
環境によって使い分けることで、同じプロジェクトのなかでも開発用・テスト用・本番用など用途に合わせた値の設定ができます。
以下は、代表的なファイル構成例です。
my-nextjs-project/ ├─ .env ├─ .env.local ├─ .env.production ├─ next.config.js └─ pages/
.env
:プロジェクト全体で共通する環境変数を記述します.env.local
:ローカル開発専用の情報を含むファイルです.env.production
:本番環境向けの値を設定するためのファイルです
これらのファイルはデフォルトで.gitignore
に含めることが推奨されます。
Gitリポジトリ上に機密情報を残さないようにするためです。
サーバーサイド専用の環境変数
サーバーサイド専用の変数は、NEXT_PUBLIC というプレフィックスが付かない形で定義します。 これにより、ビルド時やサーバーサイドレンダリング時にのみ参照され、クライアント側には埋め込まれません。
例えば、以下のように.env
ファイルで定義できます。
# サーバーサイド専用 API_SECRET_KEY="mySecretKey" DATABASE_URL="postgres://user:pass@localhost:5432/mydb"
あとは、サーバーサイドのコード内で process.env.API_SECRET_KEY
のように参照します。
実務では、外部APIに認証するときや、データベース接続のパラメータを指定するときなどに利用されることが多いです。
こうした情報がクライアント側のソースに直接含まれないようになっているのは、セキュリティ面で重要なポイントです。
クライアントにも公開される環境変数
一方で、クライアントサイドでも環境変数を利用したいケースがあります。 Next.jsでは、NEXT_PUBLIC というプレフィックスを付与することで、ビルドした時点でクライアント側にも変数を埋め込む仕組みになっています。
例として、以下のように定義してみます。
# クライアントで参照できる環境変数 NEXT_PUBLIC_API_ENDPOINT="https://example.com/api" NEXT_PUBLIC_ANALYTICS_ID="UA-XXXXXXXXX"
その後、ページコンポーネントやクライアントサイドのロジック内で、 process.env.NEXT_PUBLIC_API_ENDPOINT
のように参照すればOKです。
クライアントサイドで使用するエンドポイントや、ユーザー追跡用のIDなど、公開しても差し支えない情報を扱うときに便利です。
ただし、ここで定義した内容は誰でも参照できる状態になるため、秘密情報を載せないようにしましょう。
実務での使用例:API連携
実務において、外部サービスのAPIを叩く場面では環境変数を使うことが多いです。 例えば、サーバーサイドでのみ使用する認証トークンや、クライアント側で利用する公開可能なエンドポイントなどを区別して定義します。
以下はサーバーサイドでの利用例です。
ビルド時に読み込まれるため、Node.js環境で process.env.XXXX
にアクセスが可能です。
// pages/api/getData.js export default async function handler(req, res) { // サーバーサイド専用の認証トークンを取得 const secretToken = process.env.API_SECRET_TOKEN; // 外部サービスへ問い合わせ const response = await fetch("https://api.example.com/data", { headers: { Authorization: `Bearer ${secretToken}`, }, }); const data = await response.json(); res.status(200).json({ data }); }
クライアントサイドからAPIを呼び出す場合は、/api/getData
のエンドポイントを叩くだけになります。
APIコールの詳細な仕組みはサーバーサイドで行っているため、クライアントに秘密のトークンが漏れる心配がありません。
実務での使用例:クライアントサイドでの設定切り替え
クライアントアプリ上で、テスト環境や本番環境のAPIエンドポイントを動的に切り替えたい場合などに、NEXT_PUBLIC のプレフィックスを活用します。 例えば、以下のような構成を想定します。
# テスト環境 NEXT_PUBLIC_API_BASE_URL="https://dev.example.com/api" # 本番環境 # NEXT_PUBLIC_API_BASE_URL="https://prod.example.com/api"
ローカル環境でのデバッグ時はテスト用のURLを有効にしておき、本番デプロイ時には該当部分を切り替えるという使い方です。
このとき、環境によって別々の.env
ファイルを用意しておくと、より安心でしょう。
クライアントのJavaScriptファイルでは、環境変数を参照してAPI呼び出し先を制御します。
// pages/index.js function HomePage() { const handleClick = async () => { const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL; const response = await fetch(`${apiUrl}/hello`); const result = await response.json(); console.log(result); }; return ( <div> <h2>トップページ</h2> <button onClick={handleClick}>API呼び出し</button> </div> ); } export default HomePage;
このように、クライアント側のコードで直接エンドポイントが設定されるため、ビルド後のソースにもその値が埋め込まれます。 したがって、ここには機密性の低い情報だけを配置してください。
環境変数とSSR・SSG
Next.jsはSSR(Server-Side Rendering)やSSG(Static Site Generation)をサポートしており、ページを生成するタイミングがプロジェクトによって異なる場合があります。 環境変数がどのタイミングで読み込まれるか、意識しておくことが大切です。
SSR : リクエストがあるたびにサーバー側でページを生成します。
その際に process.env
を参照できるので、APIキーや機密情報などを安全に使えることがメリットです。
SSG : ビルド時に静的にページを生成します。
ビルド時点の環境変数でページが固定されるため、ビルド環境によってAPIの呼び先が変わるような場合は注意が必要です。
たとえば、ビルドを行ったのがテスト用の環境であれば、ビルド後に生成されたページにはテスト用のURLがハードコードされる可能性があります。 実務ではビルド環境を正しく切り替えることによって、意図しない混在を防ぐようにしましょう。
よくあるトラブルと対策
環境変数まわりで初心者の皆さんが混乱しがちなポイントを整理してみます。
環境変数が反映されない
ビルドを行った後に.env
ファイルを修正しても、再ビルドまたは再起動をしないと反映されません。
NEXT_PUBLICが付いていないのにクライアントで参照しようとしている
サーバーサイド専用の変数はクライアント側では参照できません。 ビルドエラーになったり、参照値がundefinedになることがあります。
秘匿情報が誤ってクライアント側へ漏れている
うっかりNEXT_PUBLICを付けてしまったり、ソースコード内に直接機密情報を書いてしまうケースです。 こういった失敗を防ぐには、あらかじめ公開しても良い情報とそうでない情報をしっかり分けておく必要があります。
バージョンの違いによる設定の誤解
以前のバージョンでは動いていたコードが、最新バージョンにアップデートすると挙動が変わることもあります。 公式ドキュメントをこまめに確認しながら、設定方法を見直しましょう。
環境変数を使う際は、Gitリポジトリやログ出力などを通じて意図せず機密情報が漏れていないかもチェックする必要があります。
実務での運用上のヒント
実際にチーム開発をする場合や、本番運用をする際には、以下のような工夫をすることが考えられます。
CI/CDパイプラインの構築
ビルド時に環境変数を注入するフローを自動化し、常に正しい値が参照されるように管理します。
各環境用の変数ファイルを明確化
.env.development
, .env.staging
, .env.production
のようにファイル名を分けることが多いです。
それらを自動で切り替える仕組みを作ると便利です。
コンテナやクラウドの環境変数設定
Dockerやクラウドサービス(AWSやVercelなど)で環境変数を設定し、ソースコードには含めない方針も検討に値します。 デプロイ設定で外部から注入することで、より安全に運用できます。
レビュー体制
特に機密情報に関わる変更が行われたときは、コードレビューやペアレビューで確認し、誤った公開を防ぎます。
コード例:サーバーサイドとクライアントサイドの使い分け
最後に、サーバーサイドとクライアントサイドの両方で環境変数を使うケースを想定した簡単なコード例を紹介します。
# .env # クライアントサイドで参照する NEXT_PUBLIC_MESSAGE="クライアントサイドで表示するメッセージ" # サーバーサイドのみ SECRET_MESSAGE="これはサーバーサイド専用"
// pages/index.js import { useEffect, useState } from "react"; export default function HomePage() { const [secretData, setSecretData] = useState(null); useEffect(() => { // クライアントサイドから、サーバーサイドのAPIを呼び出す const fetchData = async () => { const res = await fetch("/api/secret"); const data = await res.json(); setSecretData(data.secret); }; fetchData(); }, []); return ( <div> <h2>トップページ</h2> <p>クライアントサイドの表示: {process.env.NEXT_PUBLIC_MESSAGE}</p> <p>サーバーサイドの取得結果: {secretData}</p> </div> ); }
// pages/api/secret.js export default function handler(req, res) { // クライアント側では参照できない環境変数 const secretMessage = process.env.SECRET_MESSAGE; res.status(200).json({ secret: secretMessage }); }
この例では、NEXT_PUBLIC_MESSAGE
はビルド時点でクライアントサイドに埋め込まれ、SECRET_MESSAGE
はサーバーサイドのみで参照されます。
SECRET_MESSAGE
を直接ブラウザで見ることはできませんが、API経由でサーバーサイドが加工した結果を返すことは可能です。
まとめ
ここまで、Next.jsでの環境変数の扱い方をサーバーサイドとクライアントサイドに分けて解説してきました。 実務では、環境ごとの設定や機密情報を管理する上で、環境変数の取り扱いが欠かせません。 とりわけAPIキーやデータベース接続情報を誤ってクライアント側に露出してしまうと、セキュリティリスクに直結します。
そのため、NEXT_PUBLIC を付けるかどうかを明確に分ける、.env
ファイルをコミットしない、バージョンごとに設定を確認するなど、基本的な運用ルールを守ることが大切ではないでしょうか。
環境変数の仕組みを正しく理解すれば、必要な情報を適切な場所で安全に使うことができます。 皆さんがNext.jsのプロジェクトを進めるときにも、このポイントを押さえてスムーズに開発してみてください。