Code Splitting & <Suspense>

How to dramatically improve your app's load time by splitting your JavaScript bundle and loading components only when needed.

React5 min readConcept 33 of 46

The Monolith Problem

By default, tools like Webpack or Vite bundle your entire React application—every page, every modal, every heavy chart library—into a single massive bundle.js file.

When a user visits your homepage, their browser has to download, parse, and execute that entire 5MB file before they can click a single button. This results in terrible Time to Interactive (TTI) scores.

Code Splitting is the process of breaking that monolith into smaller, on-demand chunks.

React.lazy() and <Suspense>

React provides a built-in way to dynamically import components using React.lazy(). Instead of importing a heavy component at the top of the file, you tell React to only fetch its JavaScript code when it's actually rendered on the screen.

While the browser is fetching that new JavaScript chunk over the network, React needs something to show the user. This is what <Suspense> does: it displays a fallback UI (like a skeleton loader or spinner) while the inner component's code is downloading.

Dynamic Imports in Action

First, dynamically import the component:

const HeavyChart = React.lazy(() => import('./HeavyChart'));

Then, wrap it in a Suspense boundary when you render it:

<Suspense fallback={<Spinner />}> <HeavyChart data={data} /> </Suspense>

If the user never navigates to the page with the chart, they never pay the performance penalty of downloading the chart library's JavaScript!

The Network Pipe

Interact with the diagram below to simulate a user loading an application over a 3G connection. Compare downloading the monolithic 5MB bundle vs loading just the 500KB shell instantly, and deferring the rest.

Interactive Diagram: The Network Pipe

Simulating a Slow 3G Connection

Elapsed Time0.0s
Network
bundle.js5.0 MB
main.js0.5 MB
chart.js4.5 MB
Browser Screen
Loading Chart...
MyApp

Analytics Dashboard

HeavyChart (Loaded)

User stares at a blank screen until the entire 5MB file downloads.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1What does `React.lazy()` actually do under the hood?
  2. 2What happens if a `React.lazy()` component is rendered, but it is NOT wrapped in a `<Suspense>` boundary anywhere in the tree?
  3. 3Where is generally the best place to introduce Code Splitting in a standard React Single Page Application?

Remember this

  • Code splitting breaks your large bundle.js into smaller, on-demand files.
  • React.lazy() allows you to dynamically import a component.
  • <Suspense> provides the fallback UI (loading state) while the code downloads.
  • Code-split at the Route level first, then on massive isolated components (like complex charts or rich text editors).
  • Modern React also uses Suspense for data fetching, not just code fetching.

Done with this concept?

Mark it complete to track your progress. No login needed.