Code splitting divides a large JavaScript bundle into smaller chunks so users do not have to download all application code before using the first screen. Route-based splitting is one of the most practical approaches.
Why code splitting matters
A large application may contain admin screens, reports, editors, charts, and other features that most users do not need immediately. Sending all of that code in the initial bundle increases download and parse work.
flowchart LR
A[Large application] --> B[Build]
B --> C[Main chunk]
B --> D[Admin chunk]
B --> E[Reports chunk]
B --> F[Editor chunk]
Dynamic import
const Reports = lazy(
() => import("./Reports")
);
Route-based splitting
const Dashboard = lazy(
() => import("./Dashboard")
);
const Reports = lazy(
() => import("./Reports")
);
<Routes>
<Route
path="/dashboard"
element={<Dashboard />}
/>
<Route
path="/reports"
element={<Reports />}
/>
</Routes>
Expected network behavior
Initial page:
main.js
dashboard.chunk.js
User opens Reports:
reports.chunk.js downloaded
User never opens Admin:
admin.chunk.js never downloaded
Common mistakes
- Splitting every tiny component.
- Creating too many chunks with little benefit.
- Forgetting a Suspense fallback.
- Ignoring network performance and bundle analysis.
Interview questions
- What is code splitting?
- Why use route-based splitting?
- What is dynamic import?
- What happens when a lazy chunk fails to load?