diagram.mmd — flowchart
Lazy Loading Components flowchart diagram

Lazy loading components is the practice of deferring the download of a component's JavaScript bundle until the component is actually needed — typically when a user navigates to a route that uses it or when the component scrolls into the viewport.

The browser can only parse and execute JavaScript after it has been downloaded. In a typical SPA built without lazy loading, the entire application's component tree is bundled into a single file downloaded on initial page load. For large applications this can mean 500 KB to several megabytes of JavaScript that the user must download before seeing any content, most of which belongs to routes they may never visit in a given session. Lazy loading solves this by splitting the bundle into smaller chunks that are downloaded on demand.

The JavaScript mechanism that enables lazy loading is the dynamic import() syntax. Unlike a static import statement at the top of a file (which the bundler includes in the initial chunk), import('./HeavyComponent') returns a Promise and signals the bundler (webpack, Vite, Rollup) to create a separate chunk for that module and all its dependencies. The chunk is downloaded over HTTP only when the import() is called at runtime.

React exposes this through React.lazy() paired with : const Modal = React.lazy(() => import('./Modal')). When React first renders , it triggers the dynamic import, and }> displays the fallback while the chunk loads. Vue supports defineAsyncComponent(() => import('./Modal.vue')) with a similar pattern. Route-based lazy loading in frameworks like Next.js and Nuxt is often configured by convention at the file-system level rather than manually.

For images and off-screen content, the native loading="lazy" attribute and IntersectionObserver API handle lazy loading without JavaScript. See Code Splitting Architecture for how dynamic imports interact with the bundler's chunk graph, and Module Bundling Workflow for how the overall bundle is constructed.

Free online editor
Edit this diagram in Graphlet
Fork, modify, and export to SVG or PNG. No sign-up required.
Open in Graphlet →

Frequently asked questions

Lazy loading components is the practice of deferring the download of a component's JavaScript bundle until the component is actually needed — typically on first render triggered by a route change or scroll-into-viewport event — rather than bundling it with the initial page load.
`React.lazy(() => import('./Modal'))` wraps a dynamic import in a React-compatible lazy component. When React first tries to render it, it throws a Promise internally, which `<Suspense>` catches and uses to display the `fallback` UI. Once the chunk loads and the Promise resolves, React re-renders the component with the now-available module.
Lazy load components that are not needed on the initial view: modal dialogs, route-level pages not visited on first load, heavy chart or editor libraries, and admin panels. Avoid lazy-loading components that are visible above the fold on initial render — the loading delay will be noticeable to users and may harm LCP.
Eager loading includes all code in the initial bundle, so it is available instantly but increases initial download and parse time. Lazy loading defers code to a separate chunk fetched on demand, reducing initial load but introducing a small delay the first time that component is needed. The right balance is to eager-load the critical path and lazy-load everything else.
mermaid
flowchart TD A[Initial Page Load] --> B[Download Initial JS Bundle Only] B --> C[App Boots and Renders Visible Route] C --> D{User navigates or component enters viewport?} D -- No --> E[Idle — No extra downloads] D -- Yes --> F[dynamic import called] F --> G{Chunk already in browser cache?} G -- Yes --> H[Load Chunk from Cache] G -- No --> I[HTTP GET — Fetch JS Chunk from Server] I --> J[Download Chunk] J --> K[Parse and Execute Chunk] H --> K K --> L[Module Registered in Runtime] L --> M{Suspense boundary present?} M -- Yes --> N[Replace Fallback with Loaded Component] M -- No --> O[Render Component Directly] style C fill:#3b82f6,color:#fff style N fill:#22c55e,color:#fff style O fill:#22c55e,color:#fff
Copied to clipboard