📑 Table of Contents
Web performance directly impacts user experience, SEO rankings, and conversion rates. Google's research shows that a 1-second delay in page load reduces conversions by 7%. This guide covers practical techniques to optimize every aspect of your site's performance.
Core Web Vitals are Google's official metrics for page experience. Meeting the "Good" thresholds directly improves your search rankings.
1. Core Web Vitals
LCP — Largest Contentful Paint
Measures loading performance. Target: under 2.5 seconds.
- Preload critical resources:
<link rel="preload"> - Optimize server response time (TTFB)
- Use CDN for static assets
- Optimize and properly size images
INP — Interaction to Next Paint
Measures interactivity. Target: under 200ms.
- Break up long tasks (> 50ms)
- Use
requestIdleCallbackfor non-critical work - Minimize main thread work
CLS — Cumulative Layout Shift
Measures visual stability. Target: under 0.1.
- Always set
widthandheighton images/video - Reserve space for dynamic content
- Avoid inserting content above existing content
2. Image Optimization
<!-- Modern responsive images -->
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Hero image"
width="1200" height="600"
loading="lazy"
decoding="async">
</picture>
<!-- Responsive sizes -->
<img srcset="small.webp 400w,
medium.webp 800w,
large.webp 1200w"
sizes="(max-width: 600px) 400px,
(max-width: 1000px) 800px,
1200px"
src="medium.webp"
alt="Responsive image">
Use AVIF format where possible — it offers 50% better compression than WebP. For above-the-fold images, add fetchpriority="high" and skip loading="lazy".
3. Code Splitting & Lazy Loading
// Dynamic imports for code splitting
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
// Route-based splitting (Next.js automatic)
// Each page in /pages or /app is auto-split
// Intersection Observer for lazy loading
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadComponent(entry.target);
observer.unobserve(entry.target);
}
});
});
4. Caching Strategies
# Optimal caching headers
# Static assets (CSS, JS, images) - aggressive caching
Cache-Control: public, max-age=31536000, immutable
# HTML pages - always revalidate
Cache-Control: no-cache
# API responses - short cache with revalidation
Cache-Control: public, max-age=60, stale-while-revalidate=300
// Service Worker for offline caching
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('v1').then((cache) => cache.put(event.request, clone));
return response;
});
})
);
});
5. Measurement Tools
- Lighthouse — Built into Chrome DevTools. Comprehensive audits.
- PageSpeed Insights — Real-world performance data from CrUX.
- WebPageTest — Detailed waterfall analysis from multiple locations.
- Chrome DevTools Performance tab — Frame-by-frame analysis.
- web-vitals library — Measure CWV programmatically.
// Measure Core Web Vitals in code
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
Performance optimization is an ongoing process, not a one-time task. Start by measuring your current metrics, then apply these techniques systematically. Even small improvements compound into significant user experience gains.