What Is Code Splitting?
Code splitting is a technique for optimizing web applications by breaking down the codebase into smaller, manageable chunks loaded separately. In Next.js, code splitting works closely with dynamic imports.
How do Next.js dynamic imports differ from static imports?
Dynamic imports use code splitting to break up the application into smaller, on-demand chunks loaded only when needed, improving page load times by initially sending less code.
Strategies for segmenting code:
- Pages: Separate bundles for different routes (Next.js default)
- Components: Individual or groups of components as separate chunks
- Libraries: Distinct chunks for third-party libraries
- Features: Code related to specific features
- User Interactions: Modules loaded based on specific user actions
Ignoring Code Splitting Risks:
- Slower Load Times & Poor UX: Users must download the entire app upfront
- Higher Bounce Rates & SEO Impact: Poor performance metrics hurt search rankings
- Security Risks: Including sensitive content in the main bundle
How to Implement Code Splitting?
next/dynamic (Pages Router)
import dynamic from 'next/dynamic';
import { useState } from 'react';
const Modal = dynamic(() => import('../components/Modal'));
export const GenericComponent = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<h1>Welcome to My Next.js App</h1>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
{isModalOpen && <Modal onClose={() => setIsModalOpen(false)} />}
</div>
);
};
Good candidates for dynamic imports:
- Heavy Components (charts, maps, editors)
- Rarely Used Components (modals, dialogs, tooltips)
- Device-Specific Components
- Auth-Based Components
- Locale-Specific UI
Disabling SSR
export const HeavyComponent = dynamic(() => import('../components/header'), {
ssr: false,
loading: () => <div>Loading…</div>
});
next/dynamic (App Router)
Next.js 13+ supports React Server Components, which are automatically code-split by default. Dynamic imports are still relevant for client components:
'use client'
import dynamic from 'next/dynamic'
const TrueClientComponent = dynamic(() => import('../components/TrueClientComponent'), { ssr: false })
Automatic Code Splitting
Each page is loaded as a separate chunk with benefits:
- Isolated Error Handling: Errors on one page don't affect others
- Optimized Bundle Size: Users load only code needed for visited pages
- Prefetching: Next.js preloads linked pages in the background
External Modules
Dynamically import heavy libraries only when needed:
import { useState, useRef } from 'react'
export const PdfComponent = () => {
const pdfLibRef = useRef(null)
const handleInputFocus = async () => {
if (!pdfLibRef.current) {
const jsPdfModule = await import('jspdf')
pdfLibRef.current = jsPdfModule.default
}
}
// ...
}
Key Points
- Use dynamic imports and next/dynamic to load code only when needed.
- Next.js automatically splits pages into separate chunks.
- Disabling SSR ensures that a component loads only on the client.
- Large conditional UI elements benefit from dynamic imports.
- Server components are automatically code-split.
- Code splitting separates pages and components into small chunks, reducing bundle size.