モノレポで開発していて、いざ本番デプロイしたら「APIが全く動かない…」という経験はありませんか?実は、多くの初心者エンジニアが陥る典型的なミスがあります。それは、フロントエンドのURLにAPIリクエストを送信してしまうという環境変数設定ミスです。
本記事では、このよくある致命的なミスの原因と対策について、実際のエラー事例とともに詳しく解説します。もしあなたが今まさにこの問題に直面しているなら、この記事が救世主になるはずです。
なぜフロントURLでAPI取得してしまうのか – 問題の本質
モノレポ分離デプロイ時に起こる典型的なURL設定ミス
モノレポ(Monorepo)では、フロントエンドとバックエンドのコードが同一リポジトリに存在します。しかし、デプロイ時には通常、それぞれを別のサーバーやプラットフォームにデプロイします:
- フロントエンド:Vercel、Netlify、Cloudflare Pagesなど
- バックエンド:Heroku、Railway、AWS、Google Cloudなど
この分離デプロイの際に、環境変数の設定を間違えると以下のような災害が発生します:
// ❌ 間違った設定例
const API_BASE_URL = 'https://my-frontend-app.vercel.app'
// これにより以下のようなリクエストが発生
fetch(`${API_BASE_URL}/api/users`)
// → https://my-frontend-app.vercel.app/api/users に送信される
// → フロントエンドサーバーにAPIリクエストを送信してしまう!
開発時は動くのに本番で壊れる理由
開発環境では問題なく動作するのに、本番デプロイすると突然APIが動かなくなる主な理由:
| 環境 | フロントエンド | バックエンド | APIベースURL |
| 開発環境 | localhost:3000 | localhost:3001 | http://localhost:3001 |
| 本番環境(間違い) | my-app.vercel.app | my-api.railway.app | https://my-app.vercel.app |
| 本番環境(正解) | my-app.vercel.app | my-api.railway.app | https://my-api.railway.app |
実際のエラー事例とその影響
ケース1: 404 Not Found エラー
最も頻繁に発生するエラーパターンです:
// 間違った環境変数設定
NEXT_PUBLIC_API_URL=https://my-frontend.vercel.app
// フロントエンドコード
const fetchUsers = async () => {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users`)
// → https://my-frontend.vercel.app/api/users にリクエスト
// → フロントエンドサーバーには /api/users は存在しない
// → 404 Not Found エラー
}
ブラウザのネットワークタブで確認できるエラー:
GET https://my-frontend.vercel.app/api/users 404 (Not Found)
404 - This page could not be found.
ケース2: CORS エラーの偽装
時には CORS エラーとして現れることもあります:
Access to fetch at 'https://my-frontend.vercel.app/api/users'
from origin 'https://my-frontend.vercel.app' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
これは実際にはCORSの問題ではなく、存在しないエンドポイントにアクセスしているだけです。
ケース3: 予期しないレスポンス
フロントエンドアプリケーションが何らかのレスポンスを返してしまう場合:
// APIのレスポンスを期待しているが...
const response = await fetch(`${API_URL}/api/users`)
const data = await response.json()
// フロントエンドサーバーから返される HTML が来る
// SyntaxError: Unexpected token < in JSON at position 0
環境変数設定の正しいパターン vs 間違いパターン
❌ よくある間違いパターン
# .env.production(間違い例)
NEXT_PUBLIC_API_URL=https://my-frontend-app.vercel.app
# ↑ フロントエンドのURLを設定してしまっている
# または
NEXT_PUBLIC_API_URL=http://localhost:3001
# ↑ 開発環境のURLをそのまま本番でも使用
✅ 正しい設定パターン
# .env.local(開発環境)
NEXT_PUBLIC_API_URL=http://localhost:3001
# .env.production(本番環境)
NEXT_PUBLIC_API_URL=https://my-backend-api.railway.app
# ↑ バックエンドの正しいURLを設定
# .env.staging(ステージング環境)
NEXT_PUBLIC_API_URL=https://staging-api.railway.app
環境別の適切な環境変数管理
| 環境 | 設定ファイル | API URL例 |
| 開発 | .env.local | http://localhost:3001 |
| ステージング | .env.staging | https://staging-api.herokuapp.com |
| 本番 | .env.production | https://api.mydomain.com |
ツール別の正しい設定方法
Vercelでのモノレポ環境変数設定
Vercelでモノレポをデプロイする際の正しい環境変数設定手順:
1. Vercel Dashboard → Project Settings → Environment Variables
2. フロントエンド用プロジェクトの環境変数を設定:
Name: NEXT_PUBLIC_API_URL
Value: https://your-backend-api.railway.app
Environment: Production
3. 設定後、必ず再デプロイを実行
4. Network タブでリクエスト先URLを確認
Turborepoでの環境変数分離テクニック
// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**"],
"env": ["NEXT_PUBLIC_API_URL"]
}
}
}
# apps/frontend/.env.production
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
# apps/backend/.env.production
PORT=3001
DATABASE_URL=postgresql://...
Next.js + Express/NestJS構成での実践例
// apps/frontend/lib/api.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'
export const apiClient = {
async get(endpoint: string) {
const response = await fetch(`${API_BASE_URL}${endpoint}`)
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`)
}
return response.json()
},
async post(endpoint: string, data: any) {
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
return response.json()
}
}
今すぐ確認!デバッグと修正手順
Network タブでAPIリクエスト先を確認する方法
- Chrome DevTools を開く:F12 または 右クリック → 検証
- Network タブを選択
- アプリケーションでAPIを呼び出す操作を実行
- リクエスト一覧を確認:URLが正しいバックエンドサーバーを指しているか
✅ 正しい例:
GET https://my-backend-api.railway.app/api/users
❌ 間違い例:
GET https://my-frontend-app.vercel.app/api/users
環境変数が正しく設定されているかの検証手順
// デバッグ用のコンソールログを追加
console.log('API_URL:', process.env.NEXT_PUBLIC_API_URL)
console.log('Current URL would be:', `${process.env.NEXT_PUBLIC_API_URL}/api/users`)
// 一時的にページに表示して確認
const DebugInfo = () => (
<div style={{background: 'yellow', padding: '10px'}}>
<p>API URL: {process.env.NEXT_PUBLIC_API_URL}</p>
</div>
)
緊急時の修正とデプロイ手順
- Vercelの場合:Environment Variables で値を修正 → Redeploy
- Netlifyの場合:Site settings → Environment variables で修正 → Trigger deploy
- 手動デプロイの場合:環境変数ファイルを修正してビルド・デプロイ
二度と間違えないためのチェックリスト
デプロイ前必須チェック項目
- □
NEXT_PUBLIC_API_URLがバックエンドのURLを指している - □ 各環境(dev/staging/prod)で異なるAPIエンドポイントが設定されている
- □ HTTPSプロトコルが正しく設定されている(本番環境)
- □ バックエンドサーバーが実際に起動している
- □ CORSが適切に設定されている
環境変数設定の命名規則とベストプラクティス
| 用途 | 推奨命名 | 例 |
| API ベースURL | NEXT_PUBLIC_API_URL | https://api.example.com |
| API キー | NEXT_PUBLIC_API_KEY | abc123def456 |
| 環境識別子 | NEXT_PUBLIC_ENV | production |
| フロントベースURL | NEXT_PUBLIC_APP_URL | https://app.example.com |
チーム開発での設定ミス防止ルール
- 環境変数テンプレート:
.env.exampleファイルでテンプレートを管理 - デプロイガイド:各環境での正しい設定値をドキュメント化
- 自動チェック:CI/CDで環境変数の妥当性をチェック
- レビュープロセス:環境変数変更時は必ずレビューを実施
実装サンプルコード集

TypeScriptでの型安全な環境変数管理
// types/env.d.ts
declare namespace NodeJS {
interface ProcessEnv {
NEXT_PUBLIC_API_URL: string
NEXT_PUBLIC_APP_URL: string
NEXT_PUBLIC_ENV: 'development' | 'staging' | 'production'
}
}
// lib/env.ts
class EnvError extends Error {
constructor(key: string) {
super(`Environment variable ${key} is not set`)
this.name = 'EnvError'
}
}
export const env = {
API_URL: (() => {
const url = process.env.NEXT_PUBLIC_API_URL
if (!url) throw new EnvError('NEXT_PUBLIC_API_URL')
return url
})(),
APP_URL: (() => {
const url = process.env.NEXT_PUBLIC_APP_URL
if (!url) throw new EnvError('NEXT_PUBLIC_APP_URL')
return url
})(),
ENV: process.env.NEXT_PUBLIC_ENV || 'development'
}
API URL設定の正しい実装例
// lib/api-config.ts
interface ApiConfig {
baseURL: string
timeout: number
retries: number
}
const createApiConfig = (): ApiConfig => {
const baseURL = process.env.NEXT_PUBLIC_API_URL
if (!baseURL) {
throw new Error(
'NEXT_PUBLIC_API_URL is not defined. Please check your environment variables.'
)
}
// URLの妥当性チェック
try {
new URL(baseURL)
} catch {
throw new Error(`Invalid API URL: ${baseURL}`)
}
return {
baseURL,
timeout: 10000,
retries: 3
}
}
export const apiConfig = createApiConfig()
// 使用例
console.log(`API requests will be sent to: ${apiConfig.baseURL}`)
環境別設定ファイルのテンプレート
# .env.example
# API設定
NEXT_PUBLIC_API_URL=http://localhost:3001
NEXT_PUBLIC_API_KEY=your_api_key_here
# アプリケーション設定
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_ENV=development
# 外部サービス
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=
NEXT_PUBLIC_SENTRY_DSN=
# .env.production
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com
NEXT_PUBLIC_ENV=production
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX
まとめ:環境変数設定ミスを根絶するために
モノレポでの分離デプロイにおける環境変数設定ミスは、多くの開発者が経験する共通の問題です。特にフロントエンドのURLにAPIリクエストを送信してしまうミスは、発見が遅れると本番環境で重大な障害を引き起こします。
重要なポイントをまとめると:
- 根本原因の理解:開発環境と本番環境でのURL設定の違いを把握する
- 適切な環境変数管理:環境ごとに正しいAPIエンドポイントを設定
- デバッグ手法の習得:Network タブでリクエスト先を確認する習慣
- 予防的対策:型安全性とチェックリストによる事前防止
- チーム共有:設定ルールとテンプレートの標準化
この記事で紹介した対策を実践すれば、もう二度と「APIが動かない!」というパニックに陥ることはないでしょう。まずは今すぐ、あなたのプロジェクトの環境変数設定を確認してみてください。
モノレポ開発は強力な手法ですが、適切な設定管理があってこそその真価を発揮します。環境変数設定を正しく理解し、確実に実装することで、安定したアプリケーション運用を実現しましょう。
