NextjsBundle Analysis

Bundle Analysis

"The app feels slow" is not actionable. "The pricing page ships a 280 KB moment library just to format one date" is. Bundle analysis is the process of turning a vague sense of slowness into a concrete, fixable list of what's actually inside your JavaScript bundles — and Next.js has an official plugin that makes this a two-minute setup.

Setting up @next/bundle-analyzer

Bash
npm install --save-dev @next/bundle-analyzer

Wrap your Next.js config with the analyzer:

TSX
// next.config.mjs
import createBundleAnalyzer from '@next/bundle-analyzer'

const withBundleAnalyzer = createBundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
})

/** @type {import('next').NextConfig} */
const nextConfig = {}

export default withBundleAnalyzer(nextConfig)

Then run a build with the ANALYZE flag set:

Bash
ANALYZE=true npm run build
Note
On Windows/PowerShell, set the environment variable separately: $env:ANALYZE="true"; npm run build, or use a small cross-platform script with the cross-env package if you want a single cross-platform npm script.

The build opens (or writes) interactive treemap HTML reports — one per bundle (client, server, and edge) — showing every module and its size as a proportionally sized rectangle.

What to look for
  • Unexpectedly large dependencies — a date/time or icon library pulled in wholesale for one small usage.

  • Duplicate chunks — the same package appearing more than once because different parts of the app import it in incompatible ways.

  • Client bundles that include code only used on the server, or vice versa, suggesting a missing 'use client' boundary or an accidental import.

  • Anything you don't recognize — a large chunk you can't explain is worth tracing back to its importing module.

Common fixes once you find a problem

Finding

Fix

Whole library imported for one function

Switch to a named/subpath import, or a lighter alternative

Heavy component only needed below the fold

next/dynamic to load it lazily

Library only used for one interactive feature

Move it behind a 'use client' boundary so it doesn't inflate every page

Duplicate versions of the same package

Deduplicate via lockfile / package resolutions

TSX
// Before: pulls in the entire library
import _ from 'lodash'
_.debounce(fn, 200)

// After: only the one function is bundled
import debounce from 'lodash/debounce'
debounce(fn, 200)
Reading the report

The analyzer produces separate reports for the client and server/edge bundles. Focus on the client report first — that's the JavaScript actually downloaded by every visitor's browser. Server bundle size matters for cold start time on serverless platforms, but it doesn't affect the user's perceived page load the same way.

Warning
Bundle analysis tells you what's in the bundle, not whether it matters. A 50 KB library used on every page is a bigger problem than a 200 KB library that only loads on a rarely visited admin page behind next/dynamic. Weigh size against how often and where a chunk is actually downloaded.
Tip
Run the analyzer as part of your normal review process for any PR that adds a new dependency, not just when performance already feels bad — it's much cheaper to catch a bloated import before it ships than after users complain.