Shrinking Your Bundle
Find what's bloating your JavaScript and fix it in 30 minutes.
Hidden Cost
A bloated bundle costs you twice: slow page loads AND higher bandwidth bills. Every extra KB is paid for on every page load.
Setup
Install the analyzer
npm install @next/bundle-analyzerConfigure Next.js
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// your existing config
});Run the analysis
ANALYZE=true npm run buildOpens an interactive treemap. Bigger rectangles = bigger problems.
The Usual Suspects
| Library | Size | Replace With |
|---|---|---|
moment | 300KB | date-fns (20KB) |
lodash (full) | 70KB | Direct imports |
| Icon libraries | 100KB+ | Direct imports or @iconify/react |
@aws-sdk/* | 500KB+ | Should be server-only |
chart.js | 200KB | Lazy load it |
Quick Fixes
Moment → date-fns
// Before
import moment from 'moment';
moment(date).format('YYYY-MM-DD');
// After
import { format } from 'date-fns';
format(date, 'yyyy-MM-dd');Lodash Direct Imports
// Before: pulls in everything
import _ from 'lodash';
_.debounce(fn, 300);
// After: just what you need
import debounce from 'lodash/debounce';
debounce(fn, 300);Icon Library Fixes
// Before: may import all icons
import { FaHome } from 'react-icons/fa';
// After: specific import path
import { FaHome } from 'react-icons/fa6';Auto-Fix with modularizeImports
Force proper tree-shaking for problem packages:
module.exports = {
modularizeImports: {
'lodash': {
transform: 'lodash/{{member}}',
},
'@mui/icons-material': {
transform: '@mui/icons-material/{{member}}',
},
'@heroicons/react/24/outline': {
transform: '@heroicons/react/24/outline/{{member}}',
},
},
};Now import { debounce } from 'lodash' automatically becomes import debounce from 'lodash/debounce'.
The Barrel File Problem
Hidden Bundle Bloat
Barrel files (index.ts re-exports) are a common source of unexpectedly large bundles.
// components/index.ts - this is a barrel file
export * from './Button';
export * from './Modal';
export * from './Chart'; // 200KB!// Importing one thing evaluates everything
import { Button } from '@/components'; // Pulls in Chart tooImport from source files directly:
import { Button } from '@/components/Button';Verification Checklist
Check for oversized packages No single package should exceed 100KB without justification. Target under 200KB total JS for initial load.
Verify tree shaking Ensure no server-only packages appear in the client bundle. Icon libraries should be properly tree-shaken.
Eliminate barrel file imports Import directly from source files, not from index.ts re-exports for large modules.
Check for duplicates Look for the same package appearing in multiple chunks with different versions.
Verify dynamic imports Heavy components should be dynamically imported. Third-party scripts should be deferred or lazy loaded.
Next: Dynamic Imports — load heavy code only when needed.
For advanced forensics: DevTools Debugging — Chrome memory dumps, chunk inspection, and LLM-powered bundle analysis.