レビュー待ち·難易度: 初級·更新: 2026-04-18

Next.js の global-error.tsx でルートレベルのエラーをキャッチする

app/global-error.tsx を使い、ルートレイアウトを含む最上位のランタイムエラーをキャッチして reset ボタンで回復する実装例。error.tsx との責務の違いも示す。

nextjserror-handling

対応バージョン

nextjs 15react 19

前提環境

Next.js App Router の error.tsx の基本を理解していること

概要

app/global-error.tsx を使い、ルートレイアウトを含む最上位のランタイムエラーをキャッチする。error.tsx はセグメント内のエラーのみ対象で、ルートレイアウト内のエラーは捕捉できない。reset 関数でリカバリーボタンを実装するパターンを示す。

インストール

# 追加インストールは不要

実装

error.tsx / global-error.tsx の責務の違い

app/
  layout.tsx          ← ルートレイアウト(global-error.tsx が守る)
  global-error.tsx    ← ルートレイアウトを含む最上位エラーをキャッチ
  error.tsx           ← app/ 直下のセグメントエラーをキャッチ
  page.tsx
  dashboard/
    layout.tsx        ← このレイアウト内のエラーは dashboard/error.tsx が守る
    error.tsx
    page.tsx

global-error.tsx

// app/global-error.tsx
"use client";

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  return (
    // global-error.tsx はルートレイアウトを置き換えるため
    // 独自の <html> と <body> が必要
    <html lang="ja">
      <body>
        <main className="flex min-h-screen flex-col items-center justify-center p-8 text-center">
          <div className="max-w-md">
            <h1 className="mb-2 text-4xl font-bold text-red-500">
              予期しないエラー
            </h1>
            <p className="mb-2 text-gray-600">
              アプリケーションで問題が発生しました。
            </p>
            {process.env.NODE_ENV === "development" && (
              <p className="mb-4 rounded bg-gray-100 p-3 text-left text-xs text-gray-500">
                {error.message}
              </p>
            )}
            {error.digest && (
              <p className="mb-4 text-xs text-gray-400">
                エラーID: {error.digest}
              </p>
            )}
            <div className="flex justify-center gap-3">
              <button
                onClick={reset}
                className="rounded bg-blue-600 px-5 py-2 text-sm text-white hover:bg-blue-700"
              >
                もう一度試す
              </button>
              <a
                href="/"
                className="rounded border border-gray-300 px-5 py-2 text-sm text-gray-700 hover:bg-gray-50"
              >
                トップに戻る
              </a>
            </div>
          </div>
        </main>
      </body>
    </html>
  );
}

セグメント用 error.tsx(比較用)

// app/error.tsx
"use client";

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  return (
    // error.tsx はルートレイアウトの中に入るため <html>/<body> 不要
    <main className="flex min-h-screen flex-col items-center justify-center p-8 text-center">
      <h2 className="mb-4 text-2xl font-semibold text-gray-800">
        エラーが発生しました
      </h2>
      <button
        onClick={reset}
        className="rounded bg-blue-600 px-5 py-2 text-sm text-white hover:bg-blue-700"
      >
        再試行
      </button>
    </main>
  );
}

エラーをわざと発生させる例(動作確認用)

// app/page.tsx
"use client";

export default function Page() {
  function throwError() {
    throw new Error("テスト用エラー");
  }

  return (
    <main className="p-8">
      <h1 className="mb-4 text-2xl font-bold">エラーテスト</h1>
      <button
        onClick={throwError}
        className="rounded bg-red-500 px-4 py-2 text-sm text-white hover:bg-red-600"
      >
        エラーを発生させる
      </button>
    </main>
  );
}

ポイント

  • global-error.tsx はルートレイアウトを置き換えるため、独自の <html><body> が必要。error.tsx はレイアウトの中に入るため不要
  • global-error.tsx本番ビルド(next build + next start)でのみ動作する。開発中(next dev)はオーバーレイが表示される
  • reset() を呼ぶとエラー境界をリセットして再レンダリングを試みる。サーバー側エラーの場合は再フェッチも行われる
  • error.digest はサーバーサイドエラーの識別子。本番環境でエラーログと照合するために使う(クライアントに詳細を出さずに済む)
  • error.tsx との使い分け: error.tsx はページやレイアウト単位のエラー。global-error.tsx はルートレイアウト自体が壊れた場合(Provider や <html> のエラー等)の最終防衛ライン

注意点

error.tsx はセグメント内のエラーをキャッチ(ルートレイアウトは対象外)。global-error.tsx はルートレイアウトを含む最上位のエラーをキャッチする。本番ビルドでのみ動作する。

関連サンプル