Contrast between React Lazy Load and React Code Splitting
Your users don't need your entire app on first load. They need the page they're looking at. Everything else can wait.
24 Apr 2024

Your users don't need your entire app on first load. They need the page they're looking at. Everything else can wait.
That's the core idea behind both lazy loading and code splitting. They sound similar — and people often conflate them — but they solve different parts of the same problem.
Lazy Loading
Lazy loading defers the loading of a component until it's actually needed. Usually that means "when the user navigates to a route" or "when a component scrolls into view."
In React, you use React.lazy() with dynamic imports:
import React, { Suspense } from 'react'
const Dashboard = React.lazy(() => import('./Dashboard'))
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
)
}
React.lazy() tells the bundler: "Don't include this in the main bundle. Load it on demand."
Suspense provides a fallback UI while the chunk loads.
Benefit: Smaller initial bundle. Faster first load.
Cost: Users see a loading state when navigating to lazy-loaded routes. On slow connections, this can feel janky.
Code Splitting
Code splitting is the bundler-level mechanism that makes lazy loading possible. It's the act of breaking your single JavaScript bundle into multiple smaller chunks.
Your bundler (Webpack, Vite, etc.) detects dynamic import() calls and creates separate files for each one. When React.lazy() triggers, the browser fetches the relevant chunk.
You can also split code manually using dynamic imports:
const module = await import('./heavyCalculation')
module.runCalculation()
Benefit: Each chunk is smaller. The browser downloads and parses less JavaScript upfront.
Cost: More HTTP requests. More chunks to manage and cache. If your chunks are too small, the overhead of fetching them outweighs the savings.
The Difference
Code splitting is a build-time strategy — the bundler decides how to slice the output.
Lazy loading is a runtime strategy — React decides when to load a chunk.
Code splitting creates the chunks. Lazy loading triggers when they get fetched.
You can have code splitting without lazy loading (preloading chunks for future navigation). You can't have lazy loading without code splitting (there's nothing to lazy-load if everything is in one bundle).
When to Use What
Use lazy loading for routes and heavy components that aren't immediately visible. Admin panels, settings pages, modals with complex forms — all good candidates.
Use code splitting everywhere your bundler supports it. Let dynamic imports do the work. Most modern bundlers handle this well out of the box.
Don't lazy-load components that appear above the fold on your landing page. That defeats the purpose — you'd be adding a loading spinner to the first thing users see.