---
title: "Navigation Boundaries"
description: "Navigation Boundaries form the core runtime error-interception and fallback mechanism in Next.js App Router. During client-side navigation, server rendering, or component tree execution, React rend..."
last_updated: "2026-09-23T10:52:03.131764+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-routing/navigation-boundaries"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/next/src/client/components/http-access-fallback/error-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx)
- [packages/next/src/client/components/dev-root-http-access-fallback-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/dev-root-http-access-fallback-boundary.tsx)
- [packages/next/src/server/app-render/app-render.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/server/app-render/app-render.tsx)
- [packages/next/src/client/components/redirect-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx)
- [packages/next/src/client/components/http-access-fallback/http-access-fallback.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts)
- [packages/next/src/client/components/error-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx)
- [packages/next/src/next-devtools/dev-overlay/container/errors.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay/container/errors.tsx)
- [packages/next/src/client/components/layout-router.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/layout-router.tsx)
- [packages/next/src/client/components/unauthorized.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/unauthorized.ts)
- [packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx)
- [packages/next/src/client/components/catch-error.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/catch-error.tsx)
- [packages/next/src/next-devtools/userspace/app/app-dev-overlay-error-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/app-dev-overlay-error-boundary.tsx)
- [packages/next/src/client/components/app-router.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/app-router.tsx)
- [packages/next/src/client/react-client-callbacks/error-boundary-callbacks.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/react-client-callbacks/error-boundary-callbacks.ts)
- [packages/next/src/client/components/builtin/unauthorized.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/builtin/unauthorized.tsx)
- [packages/next/src/client/components/forbidden.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/forbidden.ts)
- [packages/next/src/client/components/navigation.react-server.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/navigation.react-server.ts)
- [packages/next/src/client/components/errors/graceful-degrade-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/errors/graceful-degrade-boundary.tsx)
- [packages/next/src/client/components/is-next-router-error.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/is-next-router-error.ts)
- [packages/next/src/next-devtools/dev-overlay/components/overview/segment-boundary-trigger.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay/components/overview/segment-boundary-trigger.tsx)
- [packages/next/src/lib/framework/boundary-components.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/lib/framework/boundary-components.tsx)
- [packages/next/src/next-devtools/userspace/pages/pages-dev-overlay-error-boundary.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/pages/pages-dev-overlay-error-boundary.tsx)
- [packages/next/src/client/components/not-found.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/not-found.ts)
- [packages/next/src/client/components/navigation.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/navigation.ts)
- [packages/next/src/client/components/nav-failure-handler.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts)
- [packages/next/src/next-devtools/userspace/app/client-entry.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/client-entry.tsx)
- [packages/next/src/next-devtools/dev-overlay/container/runtime-error/render-error.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/dev-overlay/container/runtime-error/render-error.tsx)
- [packages/next/src/api/error.ts](https://github.com/blade47/next.js/blob/main/packages/next/src/api/error.ts)
- [packages/next/src/client/components/builtin/forbidden.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/builtin/forbidden.tsx)
- [packages/next/src/client/components/builtin/global-not-found.tsx](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/builtin/global-not-found.tsx)
</details>

## Overview

Navigation Boundaries form the core runtime error-interception and fallback mechanism in Next.js App Router. During client-side navigation, server rendering, or component tree execution, React rendering can be interrupted by explicit signals thrown from user code or unhandled exceptions. Instead of letting these runtime failures crash the entire React root, Next.js intercepts specific router control signals and HTTP access errors (`notFound()`, `forbidden()`, `unauthorized()`, and `redirect()`) via specialized React error boundaries placed around route segments.
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

This subsystem solves the problem of granular recovery: when an error or access interruption occurs in a leaf segment, it should not dismantle parent layouts or root chrome unless explicitly required.
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

The key design decisions embody throwing structured Error objects with specific `digest` signatures (such as `NEXT_HTTP_ERROR_FALLBACK;404`), inspecting these errors via `isNextRouterError`, and bubbling unhandled router signals up to parent segments while catching general JavaScript exceptions in component-level `ErrorBoundary` or `catchError` handlers.
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

```mermaid
flowchart TD
  A["User Code / Server Action"] --> B{"Thrown Exception"}
  B -->|isRedirectError| C["RedirectErrorBoundary<br>(Trigger router.push / replace)"]
  B -->|isHTTPAccessFallbackError| D["HTTPAccessFallbackBoundary<br>(Render 404 / 403 / 401 fallback)"]
  B -->|isNextRouterError == false| E["ErrorBoundary / CatchError<br>(Render errorComponent & support reset/retry)"]
  E --> F{"Is Hard Navigation Failure?"}
  F -->|Yes| G["window.location.href fallback<br>(nav-failure-handler)"]
  F -->|No| H["Display error boundary UI"]
```
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

---

## Router Error Classification and Signature Protocol

Next.js categorizes thrown routing exceptions to differentiate expected navigation interruptions from unexpected runtime application bugs.
Sources: [packages/next/src/client/components/is-next-router-error.ts:1-17](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/is-next-router-error.ts#L1-L17)

The helper function `isNextRouterError` evaluates whether an unknown thrown value is either a redirect error or an HTTP access fallback error.
Sources: [packages/next/src/client/components/is-next-router-error.ts:1-17](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/is-next-router-error.ts#L1-L17)

```typescript
export function isNextRouterError(
  error: unknown
): error is RedirectError | HTTPAccessFallbackError {
  return isRedirectError(error) || isHTTPAccessFallbackError(error)
}
```
Sources: [packages/next/src/client/components/is-next-router-error.ts:1-17](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/is-next-router-error.ts#L1-L17)

HTTP access errors are identified via a prefixed `digest` string property on standard JavaScript `Error` instances.
Sources: [packages/next/src/client/components/http-access-fallback/http-access-fallback.ts:1-62](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts#L1-L62)

The prefix constant `HTTP_ERROR_FALLBACK_ERROR_CODE` is set to `'NEXT_HTTP_ERROR_FALLBACK'`, followed by a semicolon and the HTTP status code.
Sources: [packages/next/src/client/components/http-access-fallback/http-access-fallback.ts:1-62](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts#L1-L62)

| Function / Constant | Source Representation | Purpose |
| :--- | :--- | :--- |
| `HTTP_ERROR_FALLBACK_ERROR_CODE` | `'NEXT_HTTP_ERROR_FALLBACK'` | String prefix identifying HTTP access fallback errors in digests. |
| `notFound()` | `DIGEST = 'NEXT_HTTP_ERROR_FALLBACK;404'` | Throws an error caught by `HTTPAccessFallbackBoundary` to render 404. |
| `forbidden()` | `DIGEST = 'NEXT_HTTP_ERROR_FALLBACK;403'` | Throws an error caught by `HTTPAccessFallbackBoundary` to render 403. |
| `unauthorized()` | `DIGEST = 'NEXT_HTTP_ERROR_FALLBACK;401'` | Throws an error caught by `HTTPAccessFallbackBoundary` to render 401. |

Sources: [packages/next/src/client/components/http-access-fallback/http-access-fallback.ts:1-62](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts#L1-L62)

---

## HTTP Access Fallback Boundaries (`HTTPAccessFallbackBoundary`)

The `HTTPAccessFallbackBoundary` and its underlying stateful component `HTTPAccessFallbackErrorBoundary` handle HTTP access errors such as `404 Not Found`, `403 Forbidden`, and `401 Unauthorized`.
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

When `notFound()`, `forbidden()`, or `unauthorized()` is invoked in a Server Component, Route Handler, or Server Action, it interrupts rendering by throwing a digested error.
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

`HTTPAccessFallbackErrorBoundary` catches this error in `getDerivedStateFromError`:
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

```typescript
  static getDerivedStateFromError(error: unknown) {
    if (isHTTPAccessFallbackError(error)) {
      const httpStatus = getAccessFallbackHTTPStatus(error)
      return {
        triggeredStatus: httpStatus,
      }
    }
    // Re-throw if error is not for 404
    throw error
  }
```
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

During render execution, if `triggeredStatus` is set and matches an available fallback component prop (`notFound`, `forbidden`, or `unauthorized`), the boundary injects a `<meta name="robots" content="noindex" />` tag, appends development-mode metadata tags if applicable, and renders the corresponding fallback component.
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

> [!NOTE]
> Navigation updates automatically reset the error boundary state. `getDerivedStateFromProps` compares `props.pathname` to `state.previousPathname`; if a navigation has occurred (`props.pathname !== state.previousPathname`), `triggeredStatus` is reset to `undefined`.
Sources: [packages/next/src/client/components/http-access-fallback/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/error-boundary.tsx#L1-L182)

---

## Redirect Error Boundaries (`RedirectBoundary`)

Redirect operations initiated by `redirect()` or `permanentRedirect()` throw a specialized redirect error containing target URL and redirect type metadata (`push` or `replace`).
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

The `RedirectBoundary` component intercepts these errors to execute client-side navigation transitions without requiring full page reloads.
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

The execution sequence is managed through `RedirectErrorBoundary` and `HandleRedirect`:
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

```mermaid
sequenceDiagram
  participant UserComponent as "User Component"
  participant ErrorBoundary as "RedirectErrorBoundary"
  participant Handler as "HandleRedirect"
  participant Router as "AppRouterInstance"

  UserComponent->>ErrorBoundary: throw redirect error
  ErrorBoundary->>ErrorBoundary: getDerivedStateFromError() extracts URL & type
  ErrorBoundary->>Handler: render <HandleRedirect> with URL & reset callback
  Handler->>Router: useEffect triggers startTransition() -> router.push / replace
  Handler->>ErrorBoundary: invoke reset() clearing state
```
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

If an error has already been marked as handled (`'handled' in error`), `RedirectErrorBoundary` catches the error solely to trigger a subtree remount without executing duplicate router navigation commands.
Sources: [packages/next/src/client/components/redirect-boundary.tsx:1-87](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/redirect-boundary.tsx#L1-L87)

---

## Component-Level Error Boundaries (`ErrorBoundary` and `catchError`)

General runtime errors thrown during React rendering are caught by `ErrorBoundary` (backed by `ErrorBoundaryHandler`) or the granular HOC wrapper `catchError`.
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182), [packages/next/src/client/components/catch-error.tsx:1-221](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/catch-error.tsx#L1-L221)

Both components implement guard logic in `getDerivedStateFromError` to inspect incoming exceptions:
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

```typescript
  static getDerivedStateFromError(
    thrownValue: unknown
  ): Partial<ErrorBoundaryHandlerState> {
    if (isNextRouterError(thrownValue)) {
      // Re-throw if an expected internal Next.js router error occurs
      // this means it should be handled by a different boundary (such as a NotFound boundary in a parent segment)
      throw thrownValue
    }

    return { error: { thrownValue } }
  }
```
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

> [!IMPORTANT]
> The guard `if (isNextRouterError(thrownValue)) { throw thrownValue }` is critical. It guarantees that router navigation signals (`redirect`, `notFound`, `forbidden`, `unauthorized`) are never swallowed by generic React error components, allowing them to propagate past component error boundaries straight to their respective HTTP or redirect boundary handlers.
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

When a non-router runtime error is caught, `ErrorBoundaryHandler` renders `errorStyles`, `errorScripts`, and the supplied `errorComponent`, providing an `ErrorInfo` object containing `error`, `reset`, and `retry` functions.
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

Calling `retry()` triggers an asynchronous React transition that calls `router.refresh()` alongside resetting local error state.
Sources: [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182)

---

## Navigation Failure Recovery and Hard Navigation Fallbacks

When an exception or rejection occurs while a navigation operation is pending, Next.js provides robust failure recovery via `handleHardNavError` and `useNavFailureHandler`.
Sources: [packages/next/src/client/components/nav-failure-handler.ts:1-47](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts#L1-L47)

```typescript
export function handleHardNavError(error: unknown): boolean {
  if (
    typeof window !== 'undefined' &&
    window.next.__pendingUrl &&
    createHrefFromUrl(new URL(window.location.href)) !==
      createHrefFromUrl(window.next.__pendingUrl)
  ) {
    console.error(
      `Error occurred during navigation, falling back to hard navigation`,
      error
    )
    window.location.href = window.next.__pendingUrl.toString()
    return true
  }
  return false
}
```
Sources: [packages/next/src/client/components/nav-failure-handler.ts:1-47](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts#L1-L47)

The validation check `createHrefFromUrl(new URL(window.location.href)) !== createHrefFromUrl(window.next.__pendingUrl)` ensures that a hard navigation fallback is only triggered if the current URL differs from the pending navigation target.
Sources: [packages/next/src/client/components/nav-failure-handler.ts:1-47](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts#L1-L47)

When triggered, it logs the navigation error and assigns `window.location.href` to force a full-document reload to recover to a consistent state.
Sources: [packages/next/src/client/components/nav-failure-handler.ts:1-47](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts#L1-L47)

---

## Development Diagnostics and Segment Explorers

During local development (`NODE_ENV !== 'production'`), navigation boundaries integrate with Next.js DevTools and segment explorer overlays to simulate and debug boundary states.
Sources: [packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx:1-166](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx#L1-L166)

The `SegmentStateProvider` and `SegmentBoundaryTriggerNode` allow developers to interactively toggle segment boundary types.
Sources: [packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx:1-166](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx#L1-L166)

| Segment Boundary Type | Trigger Action in DevTools |
| :--- | :--- |
| `'not-found'` | Renders `NotFoundSegmentNode`, which executes `notFound()` to test 404 boundaries. |
| `'error'` | Renders `ErrorSegmentNode`, throwing a simulated error to test `ErrorBoundary`. |
| `'loading'` | Renders `LoadingSegmentNode`, suspending indefinitely via a hanging promise. |

Sources: [packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx:1-166](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx#L1-L166)

Furthermore, `AppDevOverlayErrorBoundary` intercepts runtime errors, tracks occurrence via `RuntimeErrorHandler.hadRuntimeError = true`, and invokes `dispatcher.openErrorOverlay()` to present detailed error frames.
Sources: [packages/next/src/next-devtools/userspace/app/app-dev-overlay-error-boundary.tsx:1-104](https://github.com/blade47/next.js/blob/main/packages/next/src/next-devtools/userspace/app/app-dev-overlay-error-boundary.tsx#L1-L104)

---

## Design Trade-Offs

| Design Choice | Benefit | Cost |
| :--- | :--- | :--- |
| **String Digest Error Signatures** (`NEXT_HTTP_ERROR_FALLBACK;404`) | Enables lightweight cross-boundary type checking without heavy class inheritance or `instanceof` bundle coupling across RSC boundaries. | Relies on string parsing format stability for all internal routing control flows. |
| **Granular Segment-Level Boundaries** | Failures in leaf components or route segments are isolated to their local layout branch without breaking parent chrome. | Increases React component tree depth and boundary wrapper overhead across nested route layouts. |
| **Hard Navigation Fallback on Pending Failures** | Prevents the application from getting permanently stuck in broken intermediate states during interrupted client routing transitions. | Discards client-side SPA state and forces a full browser reload when soft navigation failures occur. |

Sources: [packages/next/src/client/components/http-access-fallback/http-access-fallback.ts:1-62](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/http-access-fallback/http-access-fallback.ts#L1-L62), [packages/next/src/client/components/error-boundary.tsx:1-182](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/error-boundary.tsx#L1-L182), [packages/next/src/client/components/nav-failure-handler.ts:1-47](https://github.com/blade47/next.js/blob/main/packages/next/src/client/components/nav-failure-handler.ts#L1-L47)

## Related

- [Client App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-routing/client-app-router)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
