Code splitting is one of those techniques that's simple in concept — break your app into chunks and load only what's needed — but easy to implement badly in ways that trade one performance problem for another. The current best practices in 2026 are worth revisiting even if you set up splitting years ago.
Start with routes, not components
Route-based code splitting is almost always the right place to start, and it delivers the biggest impact for the least implementation effort. The logic is straightforward: a user on your settings page doesn't need the JavaScript for your dashboard, checkout flow, or admin panel loaded upfront. Splitting at the route boundary means each page only pulls in the code it actually needs, which is a substantial win with minimal restructuring of your codebase.
Component-based splitting — breaking individual heavy components (a rich text editor, a chart library, a modal that's rarely opened) into their own lazy-loaded chunks — is the natural next step once route splitting is in place, but it's a finer-grained optimization that's worth doing selectively rather than everywhere. Not every component benefits from being its own chunk; splitting too aggressively can add overhead from excessive network requests that outweighs the savings.
The basic implementation pattern
React.lazy paired with Suspense remains the standard mechanism for implementing splits in React. The pattern is well-established at this point: wrap a lazy-loaded component in Suspense with a fallback, and React handles showing that fallback while the chunk downloads. What's easy to get wrong isn't the mechanism itself but the surrounding details:
- Error boundaries matter as much as Suspense. Chunk loading can fail — a flaky network, an outdated cached asset pointing to a chunk that no longer exists after a deploy — and without an error boundary around your lazy-loaded components, a failed chunk load crashes the whole tree instead of failing gracefully.
- Loading states need to be meaningful, not blank. Users shouldn't see a blank screen or a broken layout while a component loads. A skeleton or spinner that matches the shape of what's loading keeps the experience from feeling broken mid-transition.
Prefetching is what separates good code splitting from great code splitting
The distinction that matters most in 2026 guidance: lazy loading alone only helps if you load things exactly when needed, which can still introduce a visible delay at the moment of navigation. Prefetching solves this by anticipating what a user will need next and loading it slightly before they ask for it — for example, prefetching a settings page's chunk the moment a user hovers over the settings link, so by the time they click, the chunk is often already cached.
The rule of thumb: use lazy loading for components users might never see (an admin panel most users never open), and prefetching for components they'll probably need soon (the next step in a checkout flow). Getting this distinction right is what makes code splitting feel invisible to the user rather than introducing its own small stutters.
The measurable impact
Proper code splitting, done with both the split and the prefetch strategy considered together, can cut initial load time by close to 40% in typical applications — a substantial improvement that directly affects how fast an app feels on first load, which is usually the moment users are most likely to bounce if something feels slow.
Practical checklist
- Split at the route level first — it's the highest-leverage, lowest-effort change.
- Add component-level splitting selectively for genuinely heavy, conditionally-rendered components (editors, charts, modals) rather than everywhere.
- Always pair
React.lazywith bothSuspense(for loading state) and an error boundary (for failed chunk loads). - Use hover, viewport-proximity, or user-flow signals to prefetch likely-next chunks rather than relying purely on reactive lazy loading.
- Measure actual load time impact after implementing — code splitting misconfigured (too granular, poor prefetch strategy) can occasionally make perceived performance worse, not better.
React Server Components change the calculus entirely
Everything above assumes a traditional client-rendered React app where every component ships as JavaScript to the browser by default. React Server Components (RSC), now stabilizing across the ecosystem in 2026, change that default fundamentally: a Server Component executes entirely on the server and sends only its rendered output to the client — its actual code never ships as part of the client bundle at all. Teams migrating meaningful portions of their component tree to Server Components report client bundle size reductions in the 60-70% range, which is a categorically different kind of win than manual code splitting, since it's not deferring when code loads, it's eliminating the need to ship that code to the browser in the first place.
The practical mental model for 2026 React codebases: RSC automatically code-splits by design, since only Client Components (anything marked with a "use client" directive) contribute to the client bundle at all. The current best-practice guidance is to push "use client" down to the smallest possible leaf components — the specific interactive button, form, or widget that genuinely needs client-side state or event handlers — while keeping layout, data-fetching, and container components as Server Components by default. This doesn't replace the route-based and component-based splitting strategies described above; it works alongside them, and for a genuinely new project it changes where the default boundary sits, from "everything ships to the client unless deliberately split" to "nothing ships to the client unless deliberately marked interactive." For an existing client-rendered app, migrating to this model is a bigger undertaking than adding React.lazy calls, but it's worth evaluating for high-traffic, performance-sensitive routes where the 60-70% bundle reduction would meaningfully move your Core Web Vitals numbers.
Sources: GreatFrontEnd — Implementing Code Splitting and Lazy Loading in React, jsmanifest — Code Splitting in 2026: Lazy Loading Done Right, OneUptime — Code Splitting and Lazy Loading in React, SitePoint — React Server Components Streaming Performance Guide 2026
Keep reading
Get new posts as they publish
No spam — just the next post, straight to your inbox.