StarterApp Docs
Performance

Bundle Analysis

Understanding and optimizing JavaScript payload size

Pro Tip

Large JavaScript bundles delay interactivity. Run ANALYZE=true pnpm build to visualize bundle composition and identify optimization opportunities.

Bundle Analysis

Time-to-interactive (TTI) measures when users can interact with your application. Large bundles delay TTI because browsers must:

Download the JavaScript

Network transfer time increases linearly with bundle size. On 3G connections, each megabyte takes several seconds.

Parse the code

JavaScript engines parse code before execution. Larger files consume more CPU time during parsing.

Execute and hydrate

React hydration matches server-rendered HTML with client-side JavaScript. Heavy bundles slow this critical process.

Running Bundle Analysis

The framework integrates @next/bundle-analyzer in both apps:

ANALYZE=true pnpm build

This command builds your application and opens an interactive visualization showing:

Package Distribution

Treemap blocks represent JavaScript modules. Larger blocks indicate heavier dependencies.

Import Paths

Colors distinguish packages. Clicking zooms into specific modules for detailed inspection.

Size Metrics

Hover over blocks to see parsed size, gzipped size, and percentage of total bundle.

Analyze production builds

Development builds include debugging tools and hot reload infrastructure. Always analyze production builds for accurate measurements.

The configuration lives in next.config.ts:

import withBundleAnalyzer from "@next/bundle-analyzer";

const bundleAnalyzerConfig =
  process.env.ANALYZE === "true"
    ? withBundleAnalyzer({ enabled: true })(nextConfig)
    : nextConfig;

export default bundleAnalyzerConfig;

Package Import Optimization

Next.js 15 includes automatic optimization for large libraries. The framework enables this for common dependencies:

experimental: {
  optimizePackageImports: ["lucide-react", ...INTERNAL_PACKAGES],
}

This configuration transforms imports like:

import { User, Settings, LogOut } from "lucide-react";

Into granular requests that include only the specific icons. Without optimization, the entire icon library ships to the client.

Verify optimization in analysis

Run bundle analysis before and after adding large dependencies. Some libraries require manual optimization through dynamic imports.

Dynamic Imports for Route Splitting

Heavy components should load on-demand rather than blocking initial page load. The framework uses dynamic imports for:

Tree Shaking with Barrel Imports

Modern bundlers eliminate unused exports through tree shaking. This works automatically for ES modules but requires careful import patterns.

// Direct imports enable tree shaking
import debounce from 'lodash-es/debounce';
import { Button } from '@workspace/ui/components/button';

// Next.js optimizes these automatically
import { User, Settings } from 'lucide-react';

Direct imports tell bundlers exactly which modules to include. Unused exports get eliminated during build.

// Barrel imports may include entire packages
import * as _ from 'lodash-es';
import * as UI from '@workspace/ui';

// Without optimizePackageImports, this ships all icons
import * as Icons from 'lucide-react';

Wildcard imports prevent tree shaking. Bundlers can't determine which exports you use.

Monorepo Package Optimization

The framework configures workspace packages for optimal bundling:

const INTERNAL_PACKAGES = ["@workspace/ui", "@workspace/security"];

transpilePackages: INTERNAL_PACKAGES,
experimental: {
  optimizePackageImports: [...INTERNAL_PACKAGES],
}

This enables:

  • Hot reloading for local packages without build steps
  • Tree shaking for workspace dependencies
  • Import optimization across the entire monorepo

Internal packages ship as TypeScript source. Next.js transpiles and optimizes them during the application build, enabling aggressive dead code elimination.

Identifying Bundle Bloat

Common Bundle Bloat Issues

Watch for these patterns in bundle analysis:

Continuous Monitoring

Bundle analysis should run regularly, not just during optimization efforts:

Add bundle size checks to CI

GitHub Actions can fail builds that exceed size thresholds. This prevents gradual regression.

Review analysis before major releases

Compare bundle composition across versions. New dependencies should justify their weight.

Monitor production bundles

Real-world bundle sizes differ from development. Production builds include optimizations development skips.

Set budget alerts

Configure bundle size budgets in next.config.ts to fail builds that exceed thresholds. This enforces performance discipline.

Next Steps