Web Performance Optimization: A Developer's Complete Guide

Site speed isn't a nice-to-have. A 1-second improvement in mobile load time increases conversions by up to 27% (Deloitte study). Google uses Core Web Vitals as a ranking signal. And users are merciless: 53% of mobile visitors abandon a page that takes more than 3 seconds to load. This guide covers every meaningful optimization you can implement, from quick wins to advanced techniques.

Core Web Vitals: The Metrics That Matter

Before optimizing, measure. Core Web Vitals are Google's three primary performance metrics, measured using real user data (CrUX) and lab tools (Lighthouse, PageSpeed Insights):

LCP
< 2.5s
Largest Contentful Paint — how fast the main content loads
INP
< 200ms
Interaction to Next Paint — responsiveness to user input
CLS
< 0.1
Cumulative Layout Shift — visual stability during load

Run PageSpeed Insights on your URL first. It will identify your specific bottlenecks. Then use this guide to fix them in order of impact.

Image Optimization: Biggest Impact, Often Overlooked

Images typically account for 50–70% of a page's total byte weight. This is where the biggest gains are.

Use Modern Image Formats

  • WebP: 25–35% smaller than JPEG/PNG with comparable quality. Supported by all modern browsers since 2020. Use for photos.
  • AVIF: 40–50% smaller than JPEG. Better quality at lower file sizes. Slightly slower encoding but worth it for static assets. Supported by Chrome, Firefox, and Safari 16+.
  • SVG: For icons, logos, and illustrations. Infinitely scalable, tiny file size for vector graphics.
<!-- Serve AVIF with WebP fallback and JPEG as last resort -->
<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="630">
</picture>

Lazy Loading

Defer loading of below-the-fold images until the user scrolls to them. Native lazy loading requires zero JavaScript:

<!-- All images below the fold -->
<img src="image.webp" alt="Description" loading="lazy" width="800" height="400">

<!-- Hero/LCP image: explicitly eager -->
<img src="hero.webp" alt="Hero" loading="eager" fetchpriority="high" width="1200" height="630">

Always specify width and height attributes — the browser uses them to reserve space before the image loads, preventing layout shift (CLS).

Responsive Images

<img
  src="photo-800.webp"
  srcset="photo-400.webp 400w, photo-800.webp 800w, photo-1600.webp 1600w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="Description"
  width="800"
  height="533">

HTTP/2 and HTTP/3

HTTP/1.1 allows only one request per TCP connection at a time, leading to "head-of-line blocking" — each request must wait for the previous one. HTTP/2 multiplexes multiple requests over a single connection simultaneously.

In practical terms: with HTTP/2, the old advice of concatenating all your CSS and JS into single files to minimize requests is no longer necessary (and can actually hurt performance by preventing caching of individual files). Serve assets separately and let multiplexing handle the parallelism.

HTTP/3 (QUIC) reduces latency further by eliminating TCP's connection setup overhead. Cloudflare, Google, and major CDNs support it automatically when enabled.

Caching: Serve Files Instantly on Repeat Visits

Proper cache headers tell browsers to store assets locally and skip the network request entirely on repeat visits.

# Apache .htaccess — aggressive caching for versioned assets
<FilesMatch "\.(css|js|woff2|jpg|webp|avif|png|svg)$">
  Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>

# Short cache for HTML (content changes more often)
<FilesMatch "\.html$">
  Header set Cache-Control "public, max-age=3600, must-revalidate"
</FilesMatch>

Use cache-busting via filename hashing (e.g., styles.a3b4c5.css) so you can set immutable, year-long caches on assets while still deploying updates. Build tools like Vite and Webpack do this automatically.

Content Delivery Networks (CDN)

A CDN distributes your static assets across servers worldwide. A user in Tokyo gets files from a nearby Tokyo edge server, not your origin in Frankfurt. This reduces latency from 200ms to 20ms for static content.

For most projects, Cloudflare's free tier is all you need. It proxies your traffic, handles CDN, provides DDoS protection, and offers automatic Brotli compression and HTTP/3. Enable it by pointing your domain's nameservers to Cloudflare — takes about 15 minutes.

Minification and Compression

Minify all CSS, JavaScript, and HTML before serving them. Remove whitespace, comments, and unnecessary characters.

  • CSS: Use cssnano or Lightning CSS in your build pipeline. For one-off files, use our CSS Minifier tool.
  • JavaScript: esbuild (fastest), Terser (most configurable), or SWC.
  • HTML: html-minifier-terser for templates.

Stack minification with Brotli compression on your server. The combination typically reduces text asset sizes by 80–90% compared to unminified, uncompressed originals.

Fixing Cumulative Layout Shift (CLS)

Layout shifts are jarring — the user goes to click something and it moves. Common causes and fixes:

  • Images without dimensions: Always specify width and height attributes. The browser reserves the right space before the image loads.
  • Web fonts causing FOUT: Use font-display: optional or font-display: swap. Preload critical fonts with <link rel="preload">.
  • Ads and embeds: Reserve the expected height using a placeholder container with min-height set to the ad size.
  • Injected content: Don't inject banners or notifications above existing content after load. Use a fixed-height container that was always there.

Font Optimization

<!-- Preload critical fonts -->
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>

<!-- CSS: use modern font-display -->
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0000-00FF; /* Latin subset only */
}

Use variable fonts where possible — one file covers all weights, reducing total font requests.

Quick Wins Checklist

  • Add fetchpriority="high" to your LCP image
  • Add loading="lazy" to all below-fold images
  • Specify width and height on all <img> elements
  • Convert images to WebP/AVIF
  • Minify CSS and JS
  • Enable Brotli compression on your server
  • Set long cache headers on static assets
  • Enable HTTP/2 on your web server
  • Put your site behind Cloudflare CDN
  • Defer non-critical JS with defer or type="module"

Need to minify CSS as part of your performance optimization workflow?

Use the Free CSS Minifier

Frequently Asked Questions

What is a good PageSpeed score?

Google PageSpeed Insights scores pages 0–100. A score of 90–100 is Good, 50–89 is Needs Improvement, and 0–49 is Poor. Aim for 90+ on both mobile and desktop. Mobile scores are typically lower because the tool simulates a slower 4G network and a mid-range device. Note that what matters most for actual users and Google rankings are your Core Web Vitals field data (LCP, INP, CLS) from the Chrome User Experience Report, not the lab score alone.

What is LCP and what should it be?

LCP stands for Largest Contentful Paint — how long it takes for the largest visible element on the page (typically a hero image or large heading) to fully render. The target is under 2.5 seconds for a Good rating; 2.5–4 seconds is Needs Improvement; over 4 seconds is Poor. To improve LCP: preload your hero image with fetchpriority="high", use a CDN, minify render-blocking CSS, and serve images in WebP or AVIF format.

Does page speed affect SEO rankings?

Yes, directly. Google has used page speed as a ranking signal since 2010 for desktop and 2018 for mobile. Since 2021, Core Web Vitals (LCP, CLS, and INP) are part of Google's Page Experience ranking signals. A slow site with good content can still rank, but when two pages are otherwise equal, the faster one will rank higher. Additionally, slow pages increase bounce rates which negatively affect engagement signals that influence rankings indirectly.

How much does page speed affect conversion rates?

Significantly. A Deloitte study found that a 0.1-second improvement in mobile load time increased conversions by 8% for retail sites. Google's research shows that as load time increases from 1 to 3 seconds, the probability of a user bouncing increases by 32%. Amazon found that every 100ms of additional latency cost 1% in sales. Faster pages consistently convert better, particularly on mobile where network conditions are variable.

What is the difference between web performance and page speed?

Page speed refers to raw load time — seconds until the page is fully loaded. Web performance is broader: it includes page speed but also covers interactivity (INP — how quickly the page responds to clicks), visual stability (CLS — whether elements jump during load), JavaScript execution efficiency, memory usage, and network request optimisation. PageSpeed Insights measures lab performance; the Chrome User Experience Report (CrUX) measures real-world field data from actual users, which is what Google uses for rankings.