100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

Code Splitting and Lazy Loading

Reduce initial bundle size in React apps using React.lazy and Suspense to load components on demand.

Performance & TestingIntermediate10 min readJul 8, 2026
Analogies

Introduction

By default, bundlers like Webpack or Vite combine your entire application into one large JavaScript bundle, which the browser must download before it can render anything. Code splitting breaks this single bundle into smaller chunks that are loaded on demand, so users only download the code needed for the page they're currently viewing. React supports this natively through React.lazy for lazily loading components and the Suspense component for showing a fallback UI while the chunk is being fetched.

🏏

Cricket analogy: Like a broadcaster who used to force viewers to download the entire day's match footage before watching, but now streams only the over you're currently watching, with a buffering graphic (Suspense) shown while that clip loads.

Syntax

jsx
import React, { Suspense, lazy } from 'react';

// Instead of a static import, use React.lazy with a dynamic import()
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));

function App({ page }) {
  return (
    <Suspense fallback={<div>Loading page...</div>}>
      {page === 'dashboard' ? <Dashboard /> : <Settings />}
    </Suspense>
  );
}

Explanation

React.lazy takes a function that must call a dynamic import() and return a Promise resolving to a module with a default export containing a React component. The bundler recognizes the dynamic import() syntax and automatically splits that component into its own chunk file. Because loading a chunk over the network is asynchronous, React needs to know what to render while waiting — that's what Suspense is for. Any lazy component must be rendered inside a Suspense boundary with a fallback prop, which specifies the UI (like a spinner or skeleton) to show until the lazy component's code has finished downloading and can render.

🏏

Cricket analogy: Like sending a scout to fetch a specific substitute player's file only when the captain calls for them (dynamic import), with the twelfth-man board (fallback) displayed on the big screen until that player's details arrive.

A very common real-world use case is route-based code splitting: lazily loading each page/route component so that visiting the homepage doesn't force users to download the code for the admin panel, settings page, or other routes they may never visit.

Example

jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Suspense, lazy } from 'react';

const Home = lazy(() => import('./pages/Home'));
const Profile = lazy(() => import('./pages/Profile'));

function AppRoutes() {
  return (
    <BrowserRouter>
      <Suspense fallback={<p>Loading page...</p>}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/profile" element={<Profile />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

Output

When the user first loads the app, only the code for the main bundle and the router are downloaded. Navigating to '/' briefly shows 'Loading page...' while the Home.chunk.js file downloads, then renders the Home page. Navigating to '/profile' triggers a separate network request for Profile's chunk, which was never downloaded until the user actually visited that route, reducing the app's initial load time.

🏏

Cricket analogy: Like a fan's app only downloading the live scorecard widget on open, then fetching the Home highlights reel only when tapped (briefly showing 'Loading highlights...'), and separately fetching Player Profile stats only when that tab is opened, keeping launch fast.

Key Takeaways

  • Code splitting breaks a single large bundle into smaller chunks loaded on demand, improving initial load performance.
  • React.lazy(() => import('./Component')) dynamically imports a component and defines a separate chunk for it.
  • Every lazy-loaded component must be rendered inside a Suspense boundary with a fallback UI.
  • Route-based code splitting (lazy-loading each page) is the most common and impactful pattern.
  • React.lazy only supports default exports; named exports require a small wrapper module.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#CodeSplittingAndLazyLoading#Code#Splitting#Lazy#Loading#StudyNotes#SkillVeris