All topics
Patternsintermediate

Error Boundaries as a Pattern

Learn how error boundary components catch rendering errors in their subtree and display a fallback UI instead of crashing the whole app.

An error boundary is a component that catches JavaScript errors thrown during rendering, in lifecycle methods, and in constructors anywhere in its child tree, logs them, and displays a fallback UI instead of letting the error crash and unmount the entire application. Without one, an uncaught render error anywhere in the tree unmounts the whole React tree, showing a blank page.

An error boundary is like a ship's bulkhead doors: if one compartment (a subtree) floods due to a hull breach (a render error), sealing that section off keeps the rest of the ship (the rest of the app) afloat and functioning, instead of the whole vessel going down.

Key Concepts

1
Crucially, error boundaries can currently only be implemented as class components, since they rely on the class lifecycle methods static getDerivedStateFromError() (to update state and render a fallback) and componentDidCatch() (to log the error). There is no hook equivalent as of React 18/19 — this is one of the few remaining legitimate reasons a modern, otherwise hooks-based codebase still needs at least one class component, usually wrapped and reused as a generic <ErrorBoundary> component (libraries like react-error-boundary provide this ready-made).
static getDerivedStateFromError()componentDidCatch()<ErrorBoundary>react-error-boundary
2
Error boundaries only catch errors during rendering — they do not catch errors in event handlers (those need a regular try/catch), asynchronous code (like inside a setTimeout or a .then()), server-side rendering, or errors thrown in the error boundary itself. This scoping is a frequent point of confusion, since developers sometimes expect an error boundary to catch every kind of runtime error in the app.
setTimeout.then()
3
Interviewers commonly ask candidates to list exactly which categories of errors an error boundary does and doesn't catch, and to explain why this pattern remains one of the few places a class component is still required in modern React.