Performance Optimization: Code Splitting and Lazy Loading

Send only the code each page needs. Code splitting and lazy loading cut JavaScript bloat and make your site faster for real visitors on real connections.

Published 6 min read
Fredy RodriguezFredy Rodriguez
Modular geometric blocks partially assembling mid-air with floating segments representing code splitting and lazy loading of JavaScript for faster website performance
Table of Contents

Most websites send their entire JavaScript codebase to every visitor, even the parts those visitors will never use. On a typical mobile page in 2024, the median JavaScript payload reached 558 KB, and roughly 44% of those bytes went unused during page load. That unused code still has to download, parse, and compile before the browser can interact with the page.

Code splitting and lazy loading are the practical tools for JavaScript performance optimization. They let you ship only what each page actually needs, right when it needs it, without removing a single feature.

This is the final part of the Performance Optimization series. Part 1 covered the Core Web Vitals scores these techniques improve, and Part 2 walked through image optimization. This post focuses on JavaScript and resource deferral.

Why bundle size is a JavaScript performance problem

A 558 KB JavaScript bundle sounds abstract until you picture the visitor: someone on an older Android phone using mobile data, searching for an HVAC company or a custom pool contractor in Houston. Their browser has to download the full bundle, parse it, and compile it before your site responds to a tap.

Large JavaScript is the primary cause of poor INP (Interaction to Next Paint), the Core Web Vital that measures how quickly your page responds to user input. Google’s guidance on optimizing INP is direct: reduce long JavaScript tasks. Sending less code on initial load is the most effective way to do that.

For Houston small businesses competing on search, slow response shows up in bounce rate, time on site, and ultimately conversion.

What code splitting does

Code splitting breaks a single JavaScript bundle into smaller chunks. The browser requests each chunk only when it is needed.

Route-based splitting is the coarsest and most impactful approach. Instead of loading the JavaScript for your pricing page, contact form, and gallery when someone lands on your homepage, the browser loads only the homepage bundle. Each additional page fetches its own chunk on demand. Modern build tools (Vite, esbuild, Webpack) support this with minimal configuration.

Component-level splitting with dynamic imports handles finer-grained deferral. A modal dialog, a date picker, a data visualization, or a video player can each live in its own chunk:

// The chart library only loads when the user opens the dashboard
const { Chart } = await import('./charts.js')

This pattern is especially useful for third-party widgets. Analytics dashboards, chat widgets, and booking systems are common sources of render-blocking code. Loading them asynchronously after the initial paint keeps your first-load experience fast while still delivering the full feature set to users who need it.

Lazy loading: deferring what is not in view

The browser loading="lazy" attribute is the simplest performance win available. It tells the browser to skip loading an image or iframe until it approaches the viewport:

<img src="team-photo.jpg" alt="Our Houston team" loading="lazy" width="800" height="450" />

For pages with multiple images, this cuts the initial payload significantly. Below-fold images, gallery thumbnails, embedded maps, and YouTube iframes are all good candidates.

One firm rule: never apply loading="lazy" to your page’s LCP image. Google’s own documentation warns that lazy loading the LCP element delays the metric and can push your LCP score above the 2.5-second threshold that separates “Good” from “Needs Improvement.” Above-the-fold images should load immediately, ideally with fetchpriority="high" on the most important one.

How these changes connect to Core Web Vitals

Code splitting and lazy loading do not exist in isolation. They are part of the same performance story as image optimization and server response time.

A smaller initial JavaScript bundle means:

  • Faster LCP because the browser is not competing with a large script download when trying to paint your hero content
  • Better INP because fewer long JavaScript tasks block the main thread during user interaction
  • Lower Total Blocking Time which Lighthouse uses as a proxy for responsiveness before real user data is available

For a Houston business owner reviewing a Lighthouse report, these show up as concrete audit items: “Reduce unused JavaScript,” “Remove render-blocking resources,” and “Avoid large network payloads.” Addressing them moves numbers that Google measures and that visitors feel.

What to check on your site today

You do not need a developer on staff to identify the problem. Two free tools do the work:

PageSpeed Insights (pagespeed.web.dev): Paste your URL, run the test, and look at the Opportunities section. “Reduce unused JavaScript” will show exactly how many kilobytes could be deferred or removed, sorted by impact.

Chrome DevTools Coverage panel: Open DevTools, go to the Coverage tab, reload the page, and see a file-by-file breakdown of which JavaScript is executed on load versus sitting idle. Scripts with high unused-bytes percentages are the best candidates for splitting or deferral.

Third-party scripts deserve particular scrutiny. A single analytics plugin, chat widget, or marketing tag loaded on every page can contribute hundreds of kilobytes of blocking code. Auditing which third parties run on which pages, and loading non-critical ones after the initial paint, is often the highest-impact intervention available.

A site built with modern tooling handles most of this automatically. Our web design work uses build pipelines that produce optimized, code-split bundles by default, so performance is built in rather than retrofitted. The Motion Giraffx site is one example of a project where progressive loading patterns kept the experience fast despite a visually rich portfolio, and the Detail Exchange rebuild addressed similar challenges on a service business site where speed directly affects lead generation.

These techniques are also the performance foundation that makes progressive web apps viable for small businesses, where fast load times on mobile networks are non-negotiable.

Frequently asked questions

Does lazy loading hurt SEO?

No. Google’s crawler renders JavaScript and can see lazy-loaded content. The one exception: never apply loading="lazy" to your above-the-fold hero image or LCP element. Doing so delays the metric Google uses to score page speed, which can hurt rankings.

What is the difference between code splitting and lazy loading?

Code splitting breaks a JavaScript bundle into smaller chunks delivered on demand. Lazy loading defers any resource (images, iframes, scripts) until the browser needs it. They solve the same problem from different angles and are often used together.

Do I need a JavaScript framework to use code splitting?

No. Dynamic imports (import()) are a native browser and Node.js feature. Frameworks like React, Vue, and Svelte make the syntax more convenient, but any modern bundler (Vite, esbuild, Webpack) supports route-based and component-level splitting out of the box.

How do I know if my site has too much JavaScript?

Run a free PageSpeed Insights test on your URL. Look for the “Reduce unused JavaScript” and “Remove render-blocking resources” audits. The Coverage panel in Chrome DevTools shows exactly which scripts are downloaded but never executed on page load.


If your site is carrying a large JavaScript load and you want to understand what to cut, start a conversation with us. Performance work is part of how we build, not an optional add-on.

Share this postTwitter / XLinkedInBluesky
Fredy Rodriguez
Fredy Rodriguez

Technical Director & Co-Founder

Runs the data-and-code side of Desque: SEO, GEO, AEO, PPC, copywriting, and the engineering behind every site we ship. Builds in Go and TypeScript.

Continue in series: Performance Optimization