Tags: web-dev concept

Code Splitting

Date: 2026-08-16


Break the bundle so each page downloads only what it needs. The gain isn’t the bytes saved on the network — it’s the parse, compile and execute time you never spend on code that page was never going to run.


What it is

Code splitting is dividing an application bundle into chunks loaded on demand, rather than shipping everything on first load.

SINGLE BUNDLE                    SPLIT BY ROUTE

app.js  820 KB                   shared.js    180 KB   every page
  every page pays for            home.js       40 KB   homepage only
  the checkout code,             category.js   90 KB   category only
  the account code,              product.js   110 KB   product only
  the admin code                 checkout.js  240 KB   checkout only

product page pays  820 KB        product page pays  290 KB

The saving compounds: those 530KB were never downloaded, never parsed, never compiled and never executed — see JavaScript Execution Cost.

The two axes

By route. The default and the biggest win. Each page loads its own chunk plus a shared core. Every meta-framework does this automatically from the file structure.

By interaction. Load a component’s code when it’s needed rather than when the page loads:

// loaded on page load — costs everyone
import SizeGuideModal from './SizeGuideModal';
 
// loaded when someone opens it — costs the people who use it
const openSizeGuide = async () => {
  const { default: SizeGuideModal } = await import('./SizeGuideModal');
  render(SizeGuideModal);
};

Good candidates: modals, video players, maps, rich text editors, date pickers, anything below the fold, anything behind a tab.

Where it goes wrong

Over-splitting. Every chunk is a request with its own round-trip latency. Fifty tiny chunks on a mobile connection is slower than five sensible ones, and it defeats compression, which works better across larger files.

Rough guide: chunks in the tens of kilobytes, not the single digits.

Waterfalls. A chunk that imports another chunk that imports a third produces sequential round trips:

BAD                           BETTER
page.js                       page.js
  → widget.js                   → widget.js  ┐ requested in parallel
      → helper.js               → helper.js  ┘
  3 sequential round trips      2 parallel

Preloading the next chunk while the current one runs is the usual mitigation — most bundlers emit modulepreload hints for this.

Splitting shared code badly. If a utility is used by four routes and ends up duplicated in four chunks, you’ve made things worse. Bundlers handle this with a shared or common chunk; check the output rather than assuming.

Splitting the critical path. Code needed for first render should be in the initial chunk. Deferring it adds a round trip before the page can paint — The Critical Rendering Path.

Verifying it worked

Bundle analysis is not optional here, because the output rarely matches the mental model:

1  generate a bundle report (webpack-bundle-analyzer, rollup-plugin-visualizer,
   or the framework's built-in build output)

2  look for: duplicated dependencies across chunks
             a single dependency dominating a chunk
             anything large in the shared chunk that only one route uses

3  DevTools → Coverage: what proportion of the loaded JS actually ran

Duplicated dependencies are the most common finding — two versions of the same library because two packages depend on different ranges. Deduplicating often saves more than any splitting decision.

Prefetching the next step

Splitting means the next page’s chunk isn’t loaded yet. For a known funnel this is worth pre-empting:

<link rel="prefetch" href="/assets/checkout.a4f2.js">

Lowest priority, fetched when idle, so the next navigation is instant. Sensible for a strongly-directional flow — basket to checkout — and wasteful when applied everywhere, because it spends the customer’s data on pages they won’t visit. See Resource Hints.

What it doesn’t fix

  • Total code volume. Splitting redistributes; it doesn’t reduce. If checkout genuinely needs 240KB, checkout is still slow
  • Third-party scripts. They’re loaded outside your bundle and unaffected — Third-Party Scripts
  • Hydration cost. Splitting reduces what’s downloaded, not necessarily what’s hydrated — Hydration, Islands Architecture