Code Splitting and Lazy Loading in React
A practical guide to ship less JavaScript up front by combining route-level and component-level lazy loading in React apps.
Di Huynh
Author
Fast experiences start with smaller bundles. Code splitting and lazy loading are two core techniques in React that help you send only what users need, when they need it.
Why Bundle Size Becomes a Problem
As apps grow, the main JavaScript bundle often includes components that users may never open in a session. Large bundles slow down initial render, especially on mobile devices and weaker networks.
Route-Level Splitting First
The easiest win is route-level splitting. In frameworks like Next.js, this is mostly automatic, but custom React apps can implement it with React.lazy and route boundaries.
import { Suspense, lazy } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
const Login = lazy(() => import("./Login"));
const Dashboard = lazy(() => import("./Dashboard"));
export default function App() {
return (
<Router>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</Suspense>
</Router>
);
}
Component-Level Lazy Loading
For heavy components inside a page, lazy loading is still useful. Examples include chart libraries, rich text editors, map components, and advanced filters.
import { useState, lazy, Suspense } from "react";
const Modal = lazy(() => import("./Modal"));
export default function App() {
const [showModal, setShowModal] = useState(false);
return (
<div>
<button onClick={() => setShowModal(true)}>Open Modal</button>
{showModal && (
<Suspense fallback={<ModalSkeleton />}>
<Modal onClose={() => setShowModal(false)} />
</Suspense>
)}
</div>
);
}
Prefetch for Likely Next Actions
Lazy loading is not only about delay. You can prefetch chunks when users hover a link or idle on a page.
// Webpack prefetch example
const Modal = lazy(() => import(/* webpackPrefetch: true */ "./Modal"));
Pro Tip: Optimization is complete only when metrics improve in production. Use Lighthouse to verify impact.
A Practical Checklist
- Split by route first.
- Lazy load heavy optional components (Charts, Editors).
- Add polished fallbacks (Skeletons).
- Prefetch likely-next chunks.
- Measure LCP and TTI metrics.