Performance engineering is not just about what you send to the browser — it is equally about how fast you send it and from where. This module covers the server and delivery layer: the infrastructure decisions that set a hard floor on how fast your pages can ever be. No amount of image optimisation or code splitting can compensate for a slow server or a misconfigured cache.
By the end of this module you will be able to diagnose TTFB problems, design a layered caching strategy, understand what a CDN actually does for SEO, and read protocol-level details in DevTools that reveal real delivery bottlenecks.
Every Core Web Vitals metric starts at the server. LCP cannot be fast if the browser is still waiting for the first byte of HTML. INP is worsened when scripts load slowly because of high latency. CLS is less predictable when resources arrive in inconsistent order due to network variance.
Googlebot also has crawl timeouts. If your server responds slowly, the render queue backs up, rendering is delayed, and indexed content can lag by days or weeks. Google has publicly acknowledged that TTFB is not a direct ranking signal, but it is the upstream dependency of every signal that is.
TTFB is the time from a browser or crawler sending an HTTP request to receiving the first byte of the response body. It encompasses:
A good TTFB target is under 800 ms as measured in the field (CrUX). Under 200 ms is excellent. Over 1800 ms is considered poor by Lighthouse/PageSpeed Insights.
Open DevTools → Network tab → click the main document request → select the Timing sub-tab. You will see a waterfall broken into phases:
Queued
Stalled
DNS Lookup ← network/DNS problem if high
Initial connection ← TCP + TLS problem if high
Waiting (TTFB) ← server processing problem if high
Content Download ← response size problem if high
The Waiting (TTFB) row isolates the server processing contribution from the network contribution. If TTFB is 600 ms but Initial connection is 400 ms, your server is actually fast — the latency is physical distance, cured by a CDN.
Caching is the practice of storing a computed or fetched response so it can be served again without recomputing it. There are multiple caching layers and each one has different properties, lifetime, and invalidation control.
Cache-Control and ETag/Last-Modified headers.Cache-Control: s-maxage, Surrogate-Control, and CDN-specific headers.
Cache-Control is the primary mechanism for communicating caching policy from server to browser and CDN. Key directives:
Cache-Control: public, max-age=31536000, immutable
public — the response may be cached by shared caches (CDN, proxy). Use for assets that are the same for every user.private — only the user's own browser should cache this. Use for authenticated/personalised responses.max-age=N — the browser considers the response fresh for N seconds.s-maxage=N — CDN-specific max-age (overrides max-age for shared caches).no-cache — the browser must revalidate with the server before using a cached response. Does not mean "never cache."no-store — never store the response at all. Use for sensitive data.immutable — tells the browser the resource will never change at this URL; do not revalidate during max-age.stale-while-revalidate=N — serve stale content for N seconds while fetching a fresh copy in the background. Excellent for reducing TTFB without sacrificing freshness.
When a cached response expires, the browser sends a conditional request. If the server confirms the content has not changed, it returns a 304 Not Modified with no body — saving bandwidth without a full round-trip. This is controlled by:
ETag: "abc123xyz"
Last-Modified: Tue, 01 Jul 2025 08:00:00 GMT
The browser sends If-None-Match: "abc123xyz" or If-Modified-Since: ... and the server decides whether to send a full response or a 304.
The hard problem in caching is not storing — it is knowing when to expire. Two main strategies:
main.a4f3c1.js). Set max-age=31536000, immutable. The browser always has the correct version because the URL changes. This is the preferred pattern for static assets.s-maxage and issue a CDN purge API call when content is published. Used for HTML documents where the URL cannot change.A CDN is a geographically distributed network of Points of Presence (PoPs) — each PoP is a cluster of servers in a data centre. When a user requests your URL, DNS routes them to the nearest PoP. If the PoP has the response cached (cache HIT), it serves it immediately, typically in single-digit milliseconds of latency. If it does not (cache MISS), it fetches from your origin server, caches it, and serves it — adding only the single origin round-trip as overhead.
For SEO, the critical insight is that Googlebot crawls from Google's own infrastructure (primarily US-based), but real users — and therefore real CrUX field data — come from everywhere. A CDN improves field data TTFB globally, which feeds into the Page Experience signal.
By default, most CDNs respect your origin's Cache-Control headers and cache accordingly. However, you can configure CDN-level rules that override or supplement them:
stale-while-revalidate=3600) to serve near-instantly while staying fresh.private headers or cookie-based bypass rules.Link: </canonical/>; rel="canonical"), X-Robots-Tag, and Vary headers must reach Google. Confirm they appear in a curl request: curl -I https://example.com/page.www and non-www, enforce the canonical variant at the CDN/DNS level, not just the CMS.The original HTTP/1.1 protocol was designed in 1997. Its fundamental limitation for modern pages is head-of-line blocking: only one request can be in flight per TCP connection at a time (browsers partially work around this by opening 6–8 parallel connections per origin, but that is a workaround, not a solution). Loading 30 assets from one origin with HTTP/1.1 is genuinely slow.
HTTP/2 (standardised 2015) introduced several fundamental improvements:
<link rel="preload">.)HTTP/2 requires HTTPS. Practically, this means that HTTPS is no longer just a security and ranking signal — it is also a prerequisite for protocol-level performance.
HTTP/3 replaces the TCP transport layer with QUIC, a UDP-based protocol designed by Google. The motivation is that HTTP/2 multiplexing eliminated application-layer head-of-line blocking, but TCP-level head-of-line blocking remained: a lost packet blocks all streams on that TCP connection.
QUIC benefits:
HTTP/3 is now supported by all major browsers and CDNs. Google itself serves from HTTP/3. Enabling it at your CDN is typically a single checkbox.
In Chrome DevTools → Network tab, right-click the column headers and add the Protocol column. You will see values like:
h2 ← HTTP/2
h3 ← HTTP/3 (QUIC)
http/1.1 ← Legacy — investigate why
If critical resources (your HTML document, main CSS, main JS) are still served over HTTP/1.1, that is a flag. It usually means the resource is being served from a different origin that has not upgraded, or your CDN/server has not enabled HTTP/2 or HTTP/3.
The server compresses the response body before sending it, and the browser decompresses it on arrival. The client advertises its supported compression algorithms in the request header:
Accept-Encoding: gzip, deflate, br
The server responds with the encoding it chose:
Content-Encoding: br
Gzip (GNU zip) is the longstanding standard, supported universally. For HTML, CSS, and JS, it typically achieves 60–80% size reduction. Configuration in Nginx:
gzip on;
gzip_types text/html text/css application/javascript application/json image/svg+xml;
gzip_min_length 1024;
gzip_comp_level 6;
Brotli (developed by Google, standardised 2016) uses a different algorithm optimised for web content. It achieves 15–25% better compression than gzip at comparable CPU cost for typical HTML/CSS/JS files. At higher compression levels it is slower to compress (suitable for pre-compressing static assets at build time) but equally fast to decompress.
Brotli is supported by all modern browsers. The browser signals support via br in Accept-Encoding. Nginx with the ngx_brotli module:
brotli on;
brotli_types text/html text/css application/javascript application/json image/svg+xml;
brotli_comp_level 6;
For static assets, pre-compress at build time and serve the .br file directly to avoid runtime CPU cost:
brotli_static on;
gzip_static on;
In Chrome DevTools Network tab, check the response headers for Content-Encoding: br or Content-Encoding: gzip. You can also compare the Size column (bytes transferred over the network) with the Content column (uncompressed size). A 100 KB HTML file served as 18 KB confirms effective Brotli compression.
From the command line:
curl -H "Accept-Encoding: br, gzip" -I https://example.com/ | grep content-encoding
stale-while-revalidatemax-age=31536000, immutableX-Robots-Tag, Vary) pass through the CDN correctly and are visible in a raw curl -I requestChoose a real page (ideally one you have access to modify, or a public page you can analyse). Work through the following steps:
curl -sI https://your-url.com/page/ and identify every cache-related header: Cache-Control, Age, ETag, X-Cache (CDN hit/miss indicator). Determine the effective cache strategy.
Content-Encoding: br. Calculate the compression ratio (Size ÷ Content).
You have mastered this module when you can:
Cache-Control header for an HTML document, a versioned JS bundle, and a private authenticated page — and explain why each differs