Lazy Loading vs. Eager Loading: How to Decide What Should Wait

By · Updated

Rule of thumb: make the first meaningful thing arrive fast, and make everything else wait its turn — the trick is knowing which is which.

The Jargonless Difference

Eager loading yells at the browser, “hey, fetch this now!” This is how you treat your hero image, critical CSS, and any asset that defines your LCP or blocks interaction. Lazy loading whispers to the browser, “fetch this when it’s almost needed...take your time...” It’s how you treat off-screen images, below-the-fold videos, and third-party embeds; why bother loading what is not yet being seen?

Why it matters: Core Web Vitals (those metrics Google cares about when ranking your site). Eager-loading the wrong things balloons network pressure and delays LCP, resulting in dismal performance scores; lazy-loading the wrong things creates “pop-in,” input delay, or SEO blind spots. This isn’t a religious war between two attributes — it’s a prioritization problem that you solve per resource.

If you want the receipts, here are excellent references: MDN on loading for images/iframes, web.dev on lazy-loading images, Chrome Developers on Priority Hints (fetchpriority), W3C preload, and Google Search Central on lazy-loading for SEO.

A Nimble Mental Model: Budget, Priority, and Going the Distance

The most useful analogy I can think of is to have the mentality of an air-traffic controller. You have a limited runway (i.e., bandwidth and CPU), a queue (parser + preload scanner), and different aircraft with different urgency and needs. Act to Improve:

  • Budget: Early milliseconds are the most valuable, so spend them on what paints fast — it is an easy and effective win
  • Priority: If it defines the first impression, boost it...If it’s decoration, defer it.
  • Distance: The further from the fold a media asset sits, the more aggressively you can lazy-load. Trust me, users will not scroll half as fast as you think.

Fun fact: browsers already automatically prioritize, but they’re guessing from context of code elements. Developers, however, can turn that guess into an educated assumption for the browser with a few simple nudges: loading, fetchpriority, and rel="preload". Used together, they make your intent unmistakable (yes, even to Safari).

Timing Eager Loading and Effective implementation

Use eager loading for assets that affect above-the-fold rendering and early interactions (in this order):

  1. Hero (LCP) image: the massive, striking image users see first.
  2. Critical User Interface (UI) icons/illustrations: they tend to be small but visually-blocking items.
  3. Critical CSS: inlined or preloaded; don’t lazy this.
  4. Fonts that paint above the fold: preload selectively to avoid conflicts.

Hero image example

<!-- In <head>: give the browser a head start -->
<link rel="preload"
      as="image"
      href="/assets/images/hero@2x.avif"
      imagesrcset="/assets/images/hero.avif 1x, /assets/images/hero@2x.avif 2x"
      imagesizes="(min-width: 1024px) 960px, 100vw">

<!-- In body: explicitly mark assets as high priority and declare sizes to avoid CLS (snapping) -->
<img
  src="/assets/images/hero.avif"
  srcset="/assets/images/hero.avif 1x, /assets/images/hero@2x.avif 2x"
  sizes="(min-width: 1024px) 960px, 100vw"
  width="1920" height="1080"
  alt="Your product in context"
  fetchpriority="high"
  decoding="async"
  loading="eager" />

Notes: fetchpriority="high" nudges the network scheduler for that single hero image (see Priority Hints). Always declare width and height to prevent layout shift. Use modern formats (AVIF/WebP) and an honest sizes value.

CSS backgrounds as heroes?

It is important to note that background images can’t use loading or fetchpriority directly, so be sure to preload them:

<link rel="preload" as="image" href="/assets/images/hero-bg.avif">

The When of Lazy Loading (Save Bandwidth, Save Sanity, Save Yourself)

Lazy-load anything that is not needed to render the first view:

  • Gallery images below the fold — blog inline images after the intro (it is worth it)
  • Embedded maps, videos, social widgets, ad slots, and analytics extras
  • Code for features users may never trigger (tooltips, carousels, charts)

Image block

<img
  src="/assets/images/case-study-1.webp"
  width="1200" height="800"
  alt="Results dashboard for client A"
  loading="lazy"
  decoding="async"
/>

Iframe block (maps, video)

<div class="aspect-video rounded-lg ring-1 ring-black/10 overflow-hidden">
  <iframe
    src="https://www.youtube-nocookie.com/embed/XXXXXXXX"
    title="Feature demo"
    loading="lazy"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen></iframe>
</div>

For SEO, Google can index lazy-loaded images when implemented with standard markup. Avoid custom JS that hides content from crawlers. See Google’s guidance on lazy-loading.

JavaScript: Eager, Defer, Async, and Lazy Hydration

JavaScript is the heaviest hitter on many sites, the real meat-and-potatoes of performance. Treat it like luggage on a small plane: only the essentials ride up front — seriously though, externalized and pipelined to a main.js is the expectation for a reason (if not using TypeScript).

  • Core behavior: Serve with type="module" (defer by default) or defer on classic scripts. Keep it tiny.
  • Third-party / non-critical code: load after paint, on idle, or on user intent (click/hover/intersection).
  • Split features: use dynamic import() to lazy-load code when a component approaches the viewport.
<script type="module">
  // Lazy-init the gallery when it scrolled into view
  const el = document.querySelector('[data-gallery]');
  if (el && 'IntersectionObserver' in window) {
    const io = new IntersectionObserver(async ([entry]) => {
      if (entry.isIntersecting) {
        io.disconnect();
        const { initGallery } = await import('/assets/js/gallery.js');
        initGallery(el);
      }
    }, { rootMargin: '200px' });
    io.observe(el);
  }
</script>

Bonus: If a module is definitely needed on first view, give it a head start with <link rel="modulepreload">. If it’s not essential, keep it lazy to protect INP (Interaction to Next Paint).

Common Anti-Patterns (AKA: How Sites Accidentally Get Slow)

  • Lazy-loading the LCP image: Your hero should never wait.
  • Omitting intrinsic sizes: No width/height means CLS nightmares.
  • Preloading everything: Turns your runway into a parking lot, so preload only what paints first view.
  • Carousels that lazy-load the “current” slide: Users see a spinner instead of content.
  • Third-party widgets early: Treat them as guests. They don’t board before the crew.
  • JS-only lazy logic: Native loading="lazy" is simpler; JS should enhance projects, not replace the basics.

Loading Decision Tree (Use This in Code Review)

  1. Will this asset be visible above the fold? Yes → eager. No → keep evaluating.
  2. Does it meaningfully affect first impression (LCP/First Paint)? Yes → eager + maybe fetchpriority="high". No → lazy.
  3. Can it be user-triggered? Yes → lazy import; maybe load on hover/click.
  4. Is it third-party? Yes → load after paint or on interaction; sandbox iframes; set loading="lazy".
  5. Have you declared width/height? If not, fix it before shipping.

Measure What Matters (and Don’t Chase Ghosts)

Use lab tools for direction (not as the law), then confirm observations in the real environment. In Chrome DevTools, record a Performance trace and open the “Largest Contentful Paint” overlay to verify your LCP element and its load chain. In Lighthouse or PageSpeed Insights, watch the “opportunities” tied to render-blocking resources. On repeat views, confirm that lazy-loaded assets don’t regress INP via main-thread blocks.

  • LCP target: ≤ 2.5s on mobile.
  • CLS target: ≤ 0.05 (sizes + aspect ratios).
  • INP target: ≤ 200ms (defer long tasks, lazy-hydrate).

For implementation details on lazy images, see web.dev. For the loading attribute’s behavior across elements, check MDN. And when you need an early boost for a critical asset, use preload plus priority hints.

SEO: Lazy-Loading Without Harming Your Visibility

Search engines are fine with native lazy loading. Where teams trip-up is with custom JavaScript that withholds markup until after interaction, or swaps src for data-src without a noscript fallback. If the HTML isn’t in the DOM then crawlers may miss it — or, if you are lucky, rank it later.

  • Prefer native loading="lazy" over bespoke JS.
  • Keep semantic HTML (real <img>, <h* headings, lists).
  • For mission-critical imagery (product, article lead), don’t lazy-load at all.
  • For complex client-side rendering, ensure server-rendered HTML exists.

See Google’s guidelines on lazy-loading for Search.

Copy-Paste Checklist (Use on Every Page)

  • Mark the intended LCP element. Ensure it’s not lazy-loaded.
  • Add fetchpriority="high" to the LCP image; preload background heroes.
  • Declare width/height (or aspect-ratio) for all media.
  • Use loading="lazy" for below-the-fold images and every iframe.
  • Split JS: ship core with type="module", lazy-import features on demand.
  • Audit third-party scripts. Load on interaction or after first paint.
  • Measure LCP/CLS/INP in DevTools and field data. Iterate.

Bottom Line: Treat Priority Like a Product Decision

Lazy vs. eager isn’t about zealotry; it’s about sequence. Put what matters first on the runway, and make the rest queue up like pros. Your pages will feel snappy, stable, and trustworthy—and that’s what converts.

If you’ve ever stared at a waterfall chart wondering where your time went, this is your lever. Make one thing fast, then scale the discipline across your site. That’s how you stack wins: one prioritized byte at a time.

References

Spot an error or a better angle? Tell me and I’ll update the piece. I’ll credit you by name—or keep it anonymous if you prefer. Accuracy > ego.

Portrait of Mason Goulding

Mason Goulding · Founder, Maelstrom Web Services

Builder of fast, hand-coded static sites with SEO baked in. Stack: Eleventy · Vanilla JS · Netlify · Figma

With 10 years of writing expertise and currently pursuing advanced studies in computer science and mathematics, Mason blends human behavior insights with technical execution. His Master’s research at CSU–Sacramento examined how COVID-19 shaped social interactions in academic spaces — see his thesis on Relational Interactions in Digital Spaces During the COVID-19 Pandemic . He applies his unique background and skills to create successful builds for California SMBs.

Every build follows Google’s E-E-A-T standards: scalable, accessible, and future-proof.