Error Boundaries
Catch rendering errors gracefully and build resilient UI with error boundaries and recovery flows.
What Error Boundaries Catch
Error boundaries catch JavaScript errors in child component trees during rendering, lifecycle methods, and constructors. They do not catch errors in event handlers, async code, SSR, or boundaries themselves.
Implement with class components (`getDerivedStateFromError`, `componentDidCatch`) or community hooks wrapping the same APIs. React 19 improves error reporting but boundaries remain class-based for now in many setups.
- Catch render/lifecycle errors in children
- Do not catch event handler errors
- Class components or wrapper libraries
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
componentDidCatch(error, info) { logError(error, info); }
}Granular Boundary Placement
Wrap independent features in separate boundaries so one widget failure does not white-screen the entire app. Route-level boundaries in Next.js (`error.tsx`) isolate page failures.
Balance granularity — too many boundaries add noise; too few lose resilience. Place boundaries around third-party widgets, chart libraries, and experimental features.
- Per-feature isolation
- Next.js error.tsx per route
- Wrap risky third-party widgets
Fallback UI and Recovery
Show actionable fallback UI: what failed, retry button, link home. Reset boundary state on retry by changing key or calling reset function if using react-error-boundary library.
Log errors to Sentry/Datadog in componentDidCatch with component stack. Include user context and route for reproduction without exposing stack traces to users.
- Actionable fallback with retry
- Log to monitoring service
- No stack traces shown to users
Errors Outside Boundaries
Event handler errors need try/catch within handlers. Async errors need catch on promises or global unhandledrejection listeners. useEffect errors bubble to nearest boundary if thrown synchronously in effect — async errors inside effects need manual catch.
Establish team conventions: all async event handlers wrap in try/catch with user toast on failure.
- try/catch in event handlers
- Catch async errors explicitly
- Global handler for unhandled rejections
Next.js Error Handling
App Router provides `error.tsx` (client component boundary), `global-error.tsx` (root layout failures), and `not-found.tsx` for 404s. `loading.tsx` is not error handling but pairs with Suspense for pending states.
Server Component errors propagate to nearest error boundary unless caught. Differentiate expected not-found from unexpected errors for correct status codes and UX.
- error.tsx, global-error.tsx, not-found.tsx
- Server errors bubble to boundaries
- Distinguish 404 from 500 UX