2026 guide

Website Performance Optimization

This guide covers optimizing your website performance: Core Web Vitals, image optimization and caching, each with practical code examples.

15 min read
Code examples

Why website performance matters

Website performance has been an official Google ranking factor since 2021. With Core Web Vitals, Google defined clear metrics that make user experience measurable. A slow website loses rankings, visitors and revenue.

53%
of mobile site visits are abandoned if a page takes longer than 3 seconds to load
Google/DoubleClick, 2016
up to -7%
conversion rate after a 100 ms delay in load time
Akamai, State of Online Retail Performance, 2017
2.5 s
is the LCP limit for a "good" rating at the 75th percentile of visits
Google, web.dev

In competitive markets, performance can decide whether a website succeeds or fails. A fast website helps your SEO and has a direct effect on revenue.

Largest Contentful Paint (LCP)

LCP measures how long it takes for the largest visible content element in the viewport to load. This is often a hero image, large heading, or video. Google recommends an LCP of 2.5 seconds or less.

Benchmarks

Good
≤ 2.5s
Needs improvement
2.5s - 4s
Poor
>4s

Optimization measures

1. Optimize server response time

Google's rule of thumb for TTFB (Time to First Byte) is 0.8 seconds or less. To get there, we recommend a fast hosting provider.

Nginx configuration
# Nginx Performance Tuning
worker_processes auto;
worker_connections 4096;

# Gzip Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
           application/json application/javascript application/xml+rss;

# Caching
proxy_cache_path /var/cache/nginx levels=1:2
                 keys_zone=my_cache:10m max_size=1g
                 inactive=60m use_temp_path=off;

2. Prioritize resources with preload

Preload critical resources such as hero images and important fonts.

HTML Head
<!-- Preload critical resources -->
<link rel="preload" as="image" href="/hero-image.webp"
      type="image/webp" fetchpriority="high">
<link rel="preload" as="font" href="/fonts/main.woff2"
      type="font/woff2" crossorigin>

<!-- Preconnect to external domains -->
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">

3. Optimize image delivery

Use modern image formats (WebP, AVIF) and responsive images with srcset.

HTML
<picture>
  <!-- AVIF for modern browsers -->
  <source type="image/avif"
          srcset="hero-400.avif 400w,
                  hero-800.avif 800w,
                  hero-1200.avif 1200w"
          sizes="(max-width: 600px) 400px,
                 (max-width: 1200px) 800px,
                 1200px">

  <!-- WebP Fallback -->
  <source type="image/webp"
          srcset="hero-400.webp 400w,
                  hero-800.webp 800w,
                  hero-1200.webp 1200w"
          sizes="(max-width: 600px) 400px,
                 (max-width: 1200px) 800px,
                 1200px">

  <!-- JPEG Fallback -->
  <img src="hero-800.jpg"
       alt="Hero Image"
       loading="eager"
       fetchpriority="high"
       width="1200"
       height="600">
</picture>

Interaction to Next Paint (INP)

Status October 2026: INP (Interaction to Next Paint) has been the Core Web Vital for responsiveness since 12 March 2024 and replaced FID. INP counts every interaction in a visit, FID counted only the first. Lighthouse triggers no interactions, so it reports no INP. In the lab, Total Blocking Time is a rough stand-in. Reliable INP numbers come from field data such as PageSpeed Insights and Search Console.

INP measures how long the page takes to respond visibly to clicks, taps and key presses during the whole visit, and reports one of the slowest interactions. A good INP is 200 ms or less; above 500 ms counts as poor.

Optimization measures

1. Reduce JavaScript execution

Large amounts of JavaScript block the main thread, so split your code and lazy-load what you can.

Webpack/Vite Config
// Dynamic Imports for code splitting
const HeavyComponent = lazy(() => import('./HeavyComponent'));

// React.lazy with Suspense
<Suspense fallback={<Loading />}>
  <HeavyComponent />
</Suspense>

// Webpack Magic Comments for chunk names
import(/* webpackChunkName: "analytics" */ './analytics');

2. Avoid long tasks

Tasks over 50ms block user interactions. Use Web Workers for compute-intensive operations.

Web Worker Example
// Main Thread
const worker = new Worker('heavy-calculation.js');

worker.postMessage({ data: largeDataset });

worker.onmessage = (e) => {
  
  updateUI(e.data);
};

// heavy-calculation.js (Worker)
self.onmessage = (e) => {
  const result = performHeavyCalculation(e.data);
  self.postMessage(result);
};

3. Optimize third-party scripts

Load analytics, chatbots and other third-party scripts with async or defer.

HTML
<!-- Load asynchronously -->
<script async src="https://widgets.example.com/embed.js"></script>

<script defer src="/analytics.js"></script>

<script defer src="/libs/jquery.min.js"></script>

Cumulative Layout Shift (CLS)

CLS measures the visual stability of a page. Elements that "jump" during loading make for a poor user experience. A good CLS is 0.1 or less.

Common CLS causes

Images without dimensions

The browser doesn't know the size, so it reserves no space

Dynamically inserted ads or banners

Content appears after initial rendering

Web fonts without font-display

FOIT (Flash of Invisible Text) shifts layout

Solutions

1. Always specify width and height


<img src="logo.png" alt="Logo" width="200" height="50">

<img src="hero.jpg" alt="Hero" style="aspect-ratio: 16/9; width: 100%;">

.hero-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

2. Reserve space for dynamic content


.ad-placeholder {
  width: 100%;
  height: 250px;
  background: linear-gradient(90deg, #1c2333 25%, #2c3446 50%, #1c2333 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

3. Optimize font loading

/* font-display for better fallback */
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-display: swap; /* Shows fallback immediately */
  font-weight: 400;
  font-style: normal;
}

/* Preload critical fonts */
<link rel="preload" as="font"
      href="/fonts/custom.woff2"
      type="font/woff2"
      crossorigin>

Image optimization

Images often make up a large share of a page's total size, so optimizing them is one of the biggest performance levers.

Format comparison

Format Browser support File size Recommendation
AVIF All current major browsers Smallest First choice for modern browsers
WebP All current major browsers Usually smaller than JPEG Best fallback
JPEG 100% Baseline Legacy support
PNG 100% Largest Only for transparency

Optimization tools

Sharp (Node.js)

const sharp = require('sharp');

// Convert image to multiple formats
await sharp('input.jpg')
  .resize(1200, 800, { fit: 'cover' })
  .webp({ quality: 80 })
  .toFile('output-1200.webp');

await sharp('input.jpg')
  .resize(1200, 800, { fit: 'cover' })
  .avif({ quality: 70 })
  .toFile('output-1200.avif');

Squoosh (web app)

For single images, the Squoosh web app at squoosh.app shows the original and the compressed version side by side. The Squoosh CLI is no longer in the repository, so use Sharp for batch jobs.

Caching strategies

Caching reduces server load and makes your site much faster for returning visitors.

Browser caching (.htaccess)

<IfModule mod_expires.c>
  ExpiresActive On

  # Images - 1 year
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/avif "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"

  # CSS and JS - 1 month
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"

  # Fonts - 1 year
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType font/woff "access plus 1 year"

  # HTML - 1 hour
  ExpiresByType text/html "access plus 1 hour"
</IfModule>

Service Worker caching

// service-worker.js
const CACHE_NAME = 'v1';
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/scripts/main.js',
  '/images/logo.png'
];

// Install Event - Cache resources
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => cache.addAll(urlsToCache))
  );
});

// Fetch Event - Cache-First Strategy
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => {
        // Cache hit - return cached response
        if (response) return response;

        // Fetch from network
        return fetch(event.request);
      })
  );
});

CDN & edge computing

A Content Delivery Network (CDN) distributes your content across servers worldwide and delivers it from the geographically nearest location. We recommend a CDN with a strong presence in your target regions.

Cloudflare

  • Free plan available
  • DDoS protection included
  • Workers for server-side rendering at the edge

BunnyCDN

  • Pay-as-you-go pricing per GB of traffic
  • Strong performance in Europe
  • Image optimization as a paid add-on (Bunny Optimizer)

Hosting recommendations

We recommend hosting providers with servers in your target region or with global CDN coverage.

Hetzner

Servers in Germany (Nuremberg & Falkenstein)

Cloud Server
  • • Strong performance/price ratio in Germany
  • • Data stays in Germany when you pick a German location
  • • Short distance to visitors in Germany
Recommended for: SMBs, startups, high-traffic websites

DigitalOcean

Global datacenters (Frankfurt, London, NYC)

Droplet
  • • Developer-friendly platform
  • • Managed databases and Kubernetes
  • • Easy scaling and backups
Recommended for: Web applications, API hosting

Cloudflare Workers

Global edge network

Free and paid plans
  • • Works well with Astro and Next.js
  • • Automatic deployments via Git
  • • Static files are served straight from the CDN
  • • The free plan is enough for small projects
Recommended for: Modern web apps, static sites, headless CMS

Print or save the guide

Print this guide as PDF or share it with your team.

Book a first consultation

Professional performance optimization

We measure your website with Lighthouse and PageSpeed Insights, fix what slows it down and aim for green Core Web Vitals. The initial consultation is free, and afterwards you receive an individual fixed-price quote.