error.tsx per segment

Put error.tsx where a failure should stay contained.

Next.js docsGetting started · Error handling
Handle errors gracefully in Next.js applications.
GuideRead docs ↗

From next-best-practices, error-handling.md.

Where does the error land?

Toggle boundaries, then press Throw on any file.

app/Files
  • layout.tsx
  • blog/
  • layout.tsx
  • [slug]/
  • layout.tsx
  • page.tsx
/blog/hello-world3 of 3 layouts alive

app/
├── layout.tsx          // errors here → global-error.tsx
├── global-error.tsx
├── error.tsx           // catches everything below app/, root nav survives
└── blog/
    ├── layout.tsx      // errors here → app/error.tsx (the parent's boundary)
    ├── error.tsx       // catches /blog/*, sidebar survives
    └── [slug]/
        ├── layout.tsx
        ├── error.tsx   // catches /blog/[slug], post header survives
        └── page.tsx

Recover the segment only

Type a search, press Load post, then recover each pane.

Reload the pageBad
Hello world Edge cases
location.reload()0
reset()Good
Hello world Edge cases
reset()0

// app/blog/[slug]/error.tsx
'use client'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div role="alert">
      <h2>This post failed to load.</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}

The root needs global-error

Throw, then untick the shell checkbox.

app/error.tsx onlyBad
+ global-error.tsxGood

// app/global-error.tsx
'use client'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html lang="en">
      <body>
        <h2>Something went wrong.</h2>
        {error.digest && <p>Reference: {error.digest}</p>}
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

Why it matters, pros and cons

Why it matters

A boundary replaces what it wraps, so the closer it sits, the more survives.

Pros

  • Nav, sidebar and typed input survive.
  • reset() retries one segment, no reload.
  • error.digest matches the server log.

Cons

  • Each boundary is client JS and another fallback.
  • Server fetch failures need router.refresh() alongside reset().
  • error.tsx misses its own segment’s layout errors.