Dynamic Imports, Code Splitting, and Lazy Hydration
Defer non-critical components with next/dynamic and tune loading to cut time-to-interactive.
Why Code Splitting Matters in Next.js 15
Modern Next.js applications can grow large fast. Without code splitting, the browser downloads every component and dependency on the first page load — even code the user may never need.
Next.js 15 splits your bundle automatically at the route level using the App Router. But route-level splitting alone is not enough. Consider these common performance killers:
- A rich text editor loaded on every page but only used in the admin dashboard
- A heavy chart library rendered below the fold
- A modal or drawer that is never opened by most visitors
For these cases you need component-level code splitting via next/dynamic and lazy hydration strategies. Together they reduce your initial JavaScript payload, improve Time-to-Interactive (TTI), and raise your Core Web Vitals scores.
Introducing next/dynamic
next/dynamic is Next.js's wrapper around React.lazy with additional features tailored for SSR. It returns a component that is loaded on demand — the JavaScript for that component is placed in a separate chunk and only fetched when the component is about to render.
Basic usage is straightforward:
- Import
dynamicfrom'next/dynamic' - Pass a factory function that returns a dynamic
import() - Optionally pass a
loadingfallback component shown while the chunk downloads
The resulting component can be used exactly like any normal React component in your JSX.
'use client';
import dynamic from 'next/dynamic';
// The HeavyEditor chunk is NOT included in the initial bundle.
// It is fetched only when <HeavyEditor /> is first rendered.
const HeavyEditor = dynamic(
() => import('@/components/HeavyEditor'),
{
loading: () => <p>Loading editor…</p>,
}
);
export default function AdminPage() {
return (
<main>
<h1>Admin Dashboard</h1>
<HeavyEditor />
</main>
);
}All lessons in this course
- Analyzing and Shrinking the Client Bundle
- Turbopack and Compiler Configuration Deep Dive
- Module Boundaries with server-only and client-only
- Dynamic Imports, Code Splitting, and Lazy Hydration