Split route-level code
A route or screen is rarely visited and should not increase the initial JavaScript payload.
React 19+ · Function
lazy defers loading a component’s code until its first render. Wrap the lazy component, or an ancestor, in Suspense to show fallback content while the module loads.
Call lazy with a loader that returns a dynamic import. React waits until the returned component is first rendered before invoking that loader, then renders the loaded module’s default export. Because rendering suspends during loading, place the component or an ancestor inside Suspense with a fallback.
const SomeComponent = lazy(load)| Name | Type | Description |
|---|---|---|
load | () => Promise<{ default: ComponentType }> | A function returning a Promise or thenable that resolves to a module whose default export is a React component. |
A React component that suspends until the loader resolves and then renders the resolved module's default export.
import { lazy, Suspense } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
export default function App() {
return (
<Suspense fallback={<p>Loading preview…</p>}>
<MarkdownPreview />
</Suspense>
);
}The component module is requested only when MarkdownPreview is first rendered; Suspense supplies the temporary UI while that request is pending.
A route or screen is rarely visited and should not increase the initial JavaScript payload.
A large editor, chart, or preview is needed only after the user opens a feature.
A page has below-the-fold or conditional panels that are expensive to download upfront.
lazy accepts a loader function and returns a React component. React does not invoke the loader until the component is first rendered, then uses the resolved module’s default export.
Follow-up: What UI appears while loading? Rendering suspends, so the lazy component or an ancestor must be covered by Suspense with an appropriate fallback.
The loader must return a Promise or thenable that eventually resolves to a module containing a valid React component as its default export. A normal dynamic import naturally has that module shape.
Follow-up: How should a named export be adapted? Return a Promise that maps the module to an object whose default property is the named component.
Declare lazy components outside component functions, normally at module scope. React caches both the loader’s Promise and its resolved result, while a rejection is passed to the nearest Error Boundary.
Follow-up: Why combine Suspense with an Error Boundary? Suspense handles the pending state, whereas an Error Boundary handles a rejected module load.
SuspenseError Boundarydynamic import