In today’s world of lightning-fast web experiences, users won’t wait around for your app to load. Slow websites lead to high bounce rates and poor user satisfaction. One of the most effective techniques to improve load times in React apps is code splitting.
In this tutorial, you’ll learn what code splitting is, why it matters, and how to implement it in a React project using both React.lazy and dynamic imports — all while keeping performance and SEO in mind.
What is Code Splitting?
Code splitting is a technique that breaks your JavaScript bundle into smaller chunks. Instead of delivering a single large file on page load, you send only the code that’s needed for the current page. This results in:
- Faster initial load time
- Reduced bandwidth usage
- Better user experience
- Improved performance scores (LCP, TTI, etc.)
React applications (especially those built with Webpack or Vite) support this out of the box.
Why Does Code Splitting Matter?
Let’s say your app has multiple routes and each route imports large libraries like charts, maps, or video players. Without code splitting:
- Your entire app and all dependencies are downloaded at once.
- Even if the user never visits those pages, they still download that code.
- The initial JavaScript bundle can become massive — increasing First Contentful Paint (FCP) time.
By splitting code by route or component, you ensure only the needed chunks are loaded — improving speed and performance.
How Code Splitting Works in React
React introduced native support for code splitting with:
React.lazy()
Suspense
- Dynamic
import()
These tools allow components to be lazy-loaded — i.e., loaded only when they are rendered.
Setting Up Code Splitting with React.lazy()
Here’s a step-by-step example:
Before (Standard Import)
import Dashboard from './pages/Dashboard';
function App() {
return <Dashboard />;
}
This includes Dashboard in the main bundle — even if it’s not immediately needed.
After (Lazy Loaded)
import React, { Suspense, lazy } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Dashboard />
</Suspense>
);
}
What’s Happening:
lazy()
tells React to dynamically import the component.Suspense
shows a fallback UI (e.g., spinner, text) until the component is ready.- The chunk for
Dashboard
is loaded only when rendered.
Code Splitting by Route (React Router v6+)
If you’re using React Router, you can apply lazy loading at the route level:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import React, { lazy, Suspense } from 'react';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading route...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
Now your app will only load the route that the user navigates to, instead of all routes at once.
Webpack, Vite & Code Splitting
Most modern bundlers (like Webpack and Vite) automatically split code when you use dynamic imports:
const HeavyComponent = lazy(() => import(/* webpackChunkName: "heavy" */ './HeavyComponent'));
With Vite, this works even faster thanks to its native ESM support.
Best Practices for Code Splitting
- Split large components/pages – Don’t lazy-load tiny components.
- Use
Suspense
for fallbacks – Always provide a loading UI. - Group related features – Use dynamic imports to group code logically.
- Avoid lazy loading critical UI – Don’t delay above-the-fold content.
- Measure bundle size – Use tools like Webpack Bundle Analyzer or Vite Inspector.
Final Thoughts
Whether you’re working on a SPA or a large enterprise dashboard, loading only what you need can greatly improve load times, user experience, and even SEO.
By using tools like React.lazy
, Suspense
, and dynamic imports, you can build modern apps that are lean, fast, and production-ready.