
ローカルでは動くのに本番で壊れるときのNext.jsデバッグ実践ガイド
ローカルでは問題なく動くのに、本番では 500。
Next.jsを運用していると、かなりの頻度で遭遇するパターンです。
特にApp Routerのサーバー描画ルートでは、環境差がそのまま障害として表面化します。
ただし安心してください。
この種の不具合は「謎」ではなく、手順を固定すれば高確率で切り分けできます。
なぜ「ローカルOK / 本番NG」が起きるのか
主な原因は次の5つです。
- 実行環境の差分(Nodeバージョン、Edge/Nodeランタイム差)
- 環境変数の差分(未設定、値の不一致、秘密情報の形式違い)
- 実行モードの差分(
next devとnext build && next startは別物) - ルートモジュールのトップレベルimportでのクラッシュ
- 本番インフラ上での外部依存の挙動差
まず「原因カテゴリ」を確定すると、調査が速くなります。
Step 1: まずはHTTPで障害範囲を測る
コードを触る前に、ルート単位で事実確認します。
curl -s -o /dev/null -w '/blog HTTP:%{http_code}\n' 'https://example.com/blog'
curl -s -o /dev/null -w '/blog/known-post HTTP:%{http_code}\n' 'https://example.com/blog/known-post'
curl -s -o /dev/null -w '/blog/missing HTTP:%{http_code}\n' 'https://example.com/blog/definitely-missing-slug'
見方:
- 一覧は
200、詳細だけ500-> 詳細ルートの描画経路が怪しい - 存在しないslugも
500(本来は404) ->notFound()より前で落ちている可能性が高い - 特定slugのみ失敗 -> コンテンツやデータ依存の可能性
この3本だけでも、調査の方向がかなり固まります。
Step 2: ローカルでも必ず本番モードで再現確認
next devだけで安心しないことが重要です。
npm run dev
npm run build && npm run start
devは通るがbuild/startで壊れるなら、SSR/ランタイム/ビルド特有の問題です。
さらに可能なら本番と揃えます:
- Nodeメジャーバージョン
- 環境変数セット
- フラグや設定値
再現条件が揃っていないと、誤判定が増えます。
Step 3: 失敗ルートではトップレベルimportを疑う
見落としがちな典型例です。
ルートファイルのトップレベルimportが本番で例外を出すと、リクエスト内のtry/catchまで到達しません。
壊れやすい形:
import HeavyTemplate from "@/components/HeavyTemplate";
import { riskyRender } from "@/lib/risky-renderer";
より安全な形:
- ルート入口は軽量に保つ
- リスクの高い処理は必要時に遅延import
- 任意機能は失敗しても継続できる設計にする
let html: string | undefined;
try {
const { riskyRender } = await import("@/lib/risky-renderer");
html = riskyRender(content);
} catch (err) {
console.error("Optional render path failed:", err);
html = undefined;
}
Step 4: エラー処理中の「連鎖クラッシュ」を防ぐ
catch内でさらに不安定な依存(外部ロガー、認証SDKなど)を呼び、二次障害を起こすケースは多いです。
フォールバック経路は以下を徹底します。
- 副作用を最小化
- 依存を最小化
- 最低限の表示で返せるようにする
- 存在しないslugは必ず
404へ落とす
フォールバックが落ちる設計は、フォールバックではありません。
Step 5: デプロイ後スモークテストを固定化
本番デプロイ直後に、最低限これだけ実行します。
- 一覧ページ
200 - 既知slug
200 - 存在しないslug
404
簡易スクリプト例:
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="${1:-https://example.com}"
curl -s -o /dev/null -w '/blog HTTP:%{http_code}\n' "$BASE_URL/blog"
curl -s -o /dev/null -w '/blog/known-post HTTP:%{http_code}\n' "$BASE_URL/blog/known-post"
curl -s -o /dev/null -w '/blog/missing HTTP:%{http_code}\n' "$BASE_URL/blog/this-post-does-not-exist-xyz-123"
チェックリスト
- HTTPで障害範囲を先に確認したか
next build && next startで再現確認したか- 本番と同じNode/環境変数で検証したか
- 失敗ルートのトップレベルimportを見直したか
- 任意機能の描画経路を遅延import化したか
- フォールバックの依存を最小化したか
- デプロイ後スモークテストを運用に組み込んだか
本番障害は避けられません。
でも、調査手順は標準化できます。
「謎の500」をチェックリスト化できると、復旧速度も再発防止も大きく改善します。
NeoWhisperは東京都港区を拠点とする個人事業主です。税務署へ開業届を提出済みで、ソフトウェア開発・ゲーム開発・アプリ開発・Web/コンテンツ制作・翻訳サービスを提供しています。
専門分野: Next.js • TypeScript • React • Node.js • 多言語サイト • SEO • パフォーマンス最適化
NeoWhisperを信頼する理由
- 実際のプロジェクトで実証済みの本番環境対応パターン
- 多言語Webアーキテクチャ(EN/JA/AR)の深い専門知識
- パフォーマンス、SEO、ユーザー体験への注力
- オープンソースへの貢献を通じた透明性のあるアプローチ



