How to analyze bundle size in Next.js
My Next.js app has gotten noticeably slower to load over time. I suspect some heavy packages are getting bundled into every page, but I have no idea which ones. Is there a way to visualize what's actually inside my JavaScript bundles and figure out which dependencies are the problem?
Solution
Install @next/bundle-analyzer as a dev dependency:
npm install --save-dev @next/bundle-analyzer
Then wrap your Next.js config with it. The enabled flag lets you keep the wrapper
in place permanently and only activate it when you actually want to inspect the output:
// next.config.ts
import withBundleAnalyzer from '@next/bundle-analyzer'
const bundleAnalyzer = withBundleAnalyzer({ enabled: process.env.ANALYZE === 'true' })
export default bundleAnalyzer(nextConfig)
Run a production build with the flag set:
ANALYZE=true npm run build
Three HTML files will open automatically in your browser: client.html, nodejs.html,
and edge.html. For most Next.js apps, client.html is the only one worth looking at.
It shows a treemap of your client-side JavaScript. Bigger rectangles mean more bytes sent
to the browser.
If you use output: 'export' for static sites, ignore nodejs.html and edge.html
entirely. They represent server-side code that never runs.
What to look for: packages that appear inside the shared or framework chunks rather
than being isolated to the pages that actually need them. Common culprits are date libraries like moment,
icon packs where tree-shaking isn't working, chart libraries, and PDF or canvas utilities.
If html2canvas or pdfmake is sitting in your _app chunk, something is importing it
at the top level instead of lazily.
Alternative: source-map-explorer
source-map-explorer takes a different approach. Instead of hooking into the build process, it reads the production
source maps after the build and shows you what's inside each output file. It works with
any framework, not just Next.js.
First, enable production source maps in your config:
// next.config.ts
const nextConfig: NextConfig = {
productionBrowserSourceMaps: true,
}
Install the tool and run it against the built chunks:
npm install --save-dev source-map-explorer
npm run build
npx source-map-explorer '.next/static/chunks/*.js'
The output opens in a browser and looks similar to the bundle analyzer treemap. The main difference is that source-map-explorer works at the file level rather than grouping by route, so it's harder to tell which page is pulling in a given dependency. That said, some people find it easier to use for hunting down a specific module across all chunks, since you can search by module name directly.
One practical upside: if you're on a CI machine or can't easily modify next.config, you
can run source-map-explorer against any build artifacts that have source maps, without
touching the project config at all.