How to Lazy Load Images, Components, and Scripts
Lazy loading is the practice of deferring the download or execution of non-critical resources until they are actually needed. It is one of the most impactful performance strategies available: by loading only what the user needs right now, you reduce initial page weight, free up bandwidth for critical resources, and unblock the main thread for faster interactivity.
This guide covers lazy loading at three levels: images (the easiest win), components (for JavaScript-heavy applications), and third-party scripts (the most commonly overlooked). Each section includes code examples and common pitfalls.
Step-by-step guide
Lazy load below-fold images with loading=lazy
Native lazy loading is the easiest performance optimization available. Add loading="lazy" to any <img> element that is below the initial viewport. The browser will defer the download until the user scrolls within approximately 1250px of the image (the exact threshold varies by browser and connection speed).
decoding="async" alongside loading="lazy". This tells the browser to decode the image off the main thread, reducing main thread blocking and improving INP.
Lazy load components with dynamic import()
For JavaScript-heavy pages, lazy loading entire components reduces the initial bundle size and speeds up hydration. Each framework has its own pattern, but all use import() under the hood. The bundler creates a separate chunk that is only downloaded when the component is rendered.
// React
import { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
Loading chart... min-height matching the expected component height. This prevents CLS when the component loads and expands.