Stackbook Logo
scalingestablished · low operational burden

Lazy Loading

Also known as: deferred-loading, on-demand-loading

Intent

Defer loading data, code or resources until they are actually needed.

Problem

Loading everything up front slows startup and page loads and wastes memory and bandwidth on content most users never touch. Eager fetching of related records also multiplies database work.

Forces

  • •Most users use a small part of the available content
  • •Startup and first render time matter
  • •Deferred work still must feel instant when requested
  • •Hidden fetches can multiply into many round trips

Solution

Overview

Lazy loading postpones work until it is demanded. It trades a small delay at first use for a large saving up front, and it applies to code, images, data and object relationships.

How it works

Frontend example with route-level code splitting:

const Reports = lazy(() => import("./Reports"));
// downloaded only when the user opens the Reports route

Images use the loading="lazy" attribute or an intersection observer to fetch as they approach the viewport. Backend ORMs return a proxy for an association and query only when it is read:

orders = db.orders(limit=50)
for o in orders: print(o.customer.name)   # 50 extra queries

The loop above is the N plus 1 trap. Fix it with eager or batched loading for the known access pattern: one query for orders, one query for the customers by id list.

Mitigate perceived delay with prefetching. Start loading a chunk when the user hovers a link or when the browser is idle, and reserve space with skeletons or fixed image dimensions to avoid layout shift.

Pitfalls

  • Lazy loading above-the-fold content, which delays the largest paint instead of improving it.
  • Silent per-item queries in serializers and templates.
  • No retry or fallback for failed chunk downloads after a deploy replaces file names.
  • Lazy singletons that initialize concurrently without synchronization.
  • Too many tiny chunks, which cost more in requests than they save.

Key takeaways

  • Defer what is not needed for the first meaningful render.
  • Use eager or batched loading when you know you will need related data.
  • Prefetch on intent signals and reserve layout space.
  • Watch for N plus 1 in database access.

✓ When to Use

  • •Large bundles, below-the-fold images, and rarely used features
  • •Object graphs where most associations are unused
  • •Expensive initialization that some code paths never need

✗ When Not to Use

  • •Resources needed immediately for first render or the main flow
  • •Loops that would trigger one query per item (N plus 1)
  • •Latency-critical paths where deferred loading adds visible delay

Pros

  • +Faster initial load and lower memory use
  • +Saves bandwidth and backend work for unused data
  • +Lets the product grow without slowing startup

Cons

  • −Delays appear at first use
  • −Can hide N plus 1 query patterns
  • −Adds states to handle: loading, error, empty

Cost Profile

Infrastructure

Lower; less data transferred

Operational

Low

Cognitive

Medium: loading states and hidden I/O

Failure Modes

  • N plus 1 queries triggered inside a loop

  • Lazy chunk fails to load on a poor network, leaving a broken view

  • Layout shift when deferred content pops in

Real-World Examples

Alternatives

    Related Patterns

    • pagination
    • caching

    Competency Domains

    requirements constraintsdata state