Next.jsでのfetch相対パスエラーの解決
問題の説明
Next.jsのサーバーコンポーネント内でAPIルートを相対パス(/api/users
)で呼び出すと、次のエラーが発生します:
TypeError: Failed to parse URL from api/users
このエラーは以下のようなコードを実行した際に発生します:
const getUsers = async () => {
const result = await fetch('/api/users', {method: 'GET'});
if (result.ok) {
return result.json();
}
return [];
}
export default async function IndexPage() {
const users = await getUsers();
return <h1>Users: {users.length}</h1>;
}
このエラーが発生するコンテキスト
- ブラウザ環境では動作する相対パス指定が、サーバーサイド(Node.js環境)では失敗
- Next.js App Routerを使用したサーバーコンポーネントでのみ発生
- 開発環境(localhost)でも本番環境でも同様の問題が発生
エラーの根本原因
サーバー環境でのfetchの挙動の違い
ブラウザ環境では、fetch('/api/users')
は自動的に現在のドメインに対して相対的なURLを解決しますが、Node.js環境ではこの挙動はサポートされていません。
サーバーサイドで動作するNext.jsのサーバーコンポーネントでは、Node.jsのfetch実装が使用されるため、絶対URLを指定する必要があります。
効果的な解決方法
解決策1: 環境変数による絶対URLの指定
最も確実な方法は、環境変数を使用してベースURLを動的に設定することです。
const getUsers = async () => {
// 環境変数からベースURLを取得
const baseUrl = process.env.URL;
const result = await fetch(`${baseUrl}/api/users`, {
method: 'GET'
});
if (result.ok) {
return result.json();
}
return [];
}
環境変数の設定方法(.envファイル)
# ローカル開発環境
URL="http://localhost:3000"
# 本番環境(デプロイ先に合わせて変更)
URL="https://your-production-domain.com"
Vercelデプロイ時の注意点
Vercelでは環境ごとに異なるURLが生成されるため、適切な環境変数を設定してください:
# Vercelプレビュー環境
URL=https://${VERCEL_URL}
# Vercel本番環境
URL=https://your-custom-domain.com
Vercelが自動的に提供するVERCEL_URL
環境変数を活用しましょう: https://vercel.com/docs/projects/environment-variables/system-environment-variables
解決策2: サーバーコンポーネントからの直接データ取得(推奨)
Next.jsの公式ベストプラクティスでは、APIルート経由でなく直接データソースにアクセスする方法が推奨されています:
// 直接データベースや外部APIに接続
import db from '@/lib/db';
export default async function IndexPage() {
// API経由せず直接データ取得
const users = await db.users.findMany();
return <h1>Users: {users.length}</h1>;
}
直接取得が推奨される理由
- 不要なネットワークオーバーヘッドの削減
- ビルド時/実行時のパフォーマンス向上
- コードの簡素化とメンテナンス性向上
補足:ビルド時の注意点
サーバーコンポーネントから内部APIを呼び出すとビルド時に失敗するケースがあります。公式ドキュメントでは、このアプローチ自体が非推奨とされています:
⚠️ ビルド時のエラーが発生する理由
Next.jsのビルドプロセス中はアプリケーションが実行されていないため、内部APIルートへのアクセスは失敗します
非推奨パターン例
// ※ビルド時に失敗する可能性あり
export default async function BuildPage() {
const data = await fetch(`${process.env.URL}/api/data`);
// ...
}
まとめ
Next.jsサーバーコンポーネントでの相対パスfetchエラーを解決するには:
- 環境変数を使用した絶対URL指定 → クロス環境対応が可能
- API経由せず直接データ取得 → Next.jsの推奨パターン
特に、API経由でのデータ取得には余分なレイテンシが発生するため、サーバーコンポーネントから直接データソースにアクセスするアプローチが最適です。