Conceptly
← All Concepts
βœ‚οΈ

Code Splitting

performanceA performance pattern that splits bundles to reduce initial load

Code Splitting is the technique of dividing a JavaScript bundle into multiple chunks during the build process and loading each chunk at runtime only when it is needed. Instead of forcing every user to download the entire application upfront, only the code required for the current page or feature is fetched, reducing initial load time and improving perceived performance.

β–ΆArchitecture Diagram

πŸ” Structure

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

An SPA compiles the entire application into a single bundle that is downloaded all at once on the first visit. As the app grows, so does this bundle, meaning a user who only wants to see the first page must still download the code for signup, admin, and analytics dashboards. When the bundle exceeds hundreds of kilobytes, JavaScript parsing and execution time increases, and on slow networks a blank screen can persist for several seconds. Every feature addition slows down the initial load for all users.

Why did this approach emerge?

In the early web, each page loaded its own HTML and scripts separately, so bundle size was not an issue. When SPA frameworks like React and Angular arrived and the client took on the entire app logic, bundle size naturally became a performance bottleneck. Initially, vendor chunk separation was the main response, but as apps grew larger, a pattern of downloading only the necessary code per route or feature at the moment it was needed emerged. After webpack's support for dynamic import() and ECMAScript standardization (2020), this pattern became the default optimization approach across the ecosystem.

How does it work inside?

Code Splitting splits the bundle into multiple chunks during the build and loads each at runtime when needed. When the build tool encounters a dynamic import like `import('./SomeComponent')`, it separates that module and its dependencies into a distinct chunk file. The build output consists of an Initial Chunk that is essential for the first page load, and Lazy Chunks that are fetched later on demand. When the browser enters the relevant route or uses a specific feature, the JavaScript runtime issues a network request for that chunk's URL, downloads it, and executes it. Already-downloaded chunks remain in the browser cache and are not re-fetched on subsequent visits. In React, combining `React.lazy()` with `Suspense` allows this pattern to be used declaratively at the component level. Suspense handles the fallback UI shown during loading, avoiding a blank screen.

Boundaries & Distinctions

Code Splitting and Tree Shaking both reduce bundle size but take different approaches. Tree Shaking statically analyzes the code at build time and removes code that is never actually used -- the resulting bundle is one file, but with unused code stripped out. Code Splitting is not about removing code but dividing it. It defers code that the app genuinely needs but does not need right now to be fetched later. The two techniques are typically used in tandem. When used with Service Workers, strategies must be aligned. Pre-caching chunks via a Service Worker can serve Lazy Chunks instantly even offline, but failing to scope which chunks are pre-cached can bloat the cache unnecessarily. If offline support is the goal, Code Splitting and Service Worker caching strategies should be designed together. There are also situations where Code Splitting is not appropriate. If the app itself is small or most code is needed on the first page, splitting chunks only adds network round trips and can make things slower.

When should you use it?

The more pages an app has, the greater the benefit of route-based splitting. Lightweight pages like the main page, login, and product detail load fast with just the Initial Chunk, while heavy features like analytics dashboards or text editors have their cost borne only by users who actually visit those pages. The signal to consider adopting Code Splitting in practice is when Lighthouse or a bundle analyzer shows the bundle size exceeding a certain threshold, or when First Contentful Paint or Time to Interactive fall outside target ranges. The starting point is using a bundle analyzer to identify which modules are largest, then checking whether those modules are truly needed on the first screen. However, splitting too finely increases the number of chunks and network requests, which can backfire. The appropriate chunk granularity is around routes or meaningful feature groups.

SPA initial load -- downloading only the code needed for the first page the user visits to shorten TTIRoute-based splitting -- making each page component a separate chunk that loads only when that route is enteredHeavy third-party libraries -- loading large dependencies like charts or editors only on the screen where they are usedConditional features -- separating dashboards or admin screens visible only to logged-in users into their own chunks