The transport layer shapes perceived performance as much as anything in your application code. HTTP/2 introduced multiplexing so many requests share a single connection without head-of-line blocking at the HTTP layer, along with header compression via HPACK that meaningfully shrinks cookie-heavy traffic. HTTP/3 goes further by replacing TCP with QUIC over UDP, eliminating TCP head-of-line blocking entirely and shrinking handshakes with zero round-trip resumption. TLS 1.3 reduces the handshake to a single round trip and zero round trips for known sessions, and the alt-svc header lets servers advertise HTTP/3 so browsers can upgrade future connections. HTTP/2 prioritization still matters: the browser hints which resources are critical, and a well-configured server delivers them in the right order.
Compression matters as much as the protocol version. Brotli produces payloads 15 to 25 percent smaller than gzip on typical text, which often translates to hundreds of milliseconds on a slow connection. The modern strategy is to pre-compress static assets with Brotli at build time, since compression is CPU intensive, and fall back to gzip for dynamic content where per-request CPU matters. The browser negotiates encoding via Content-Encoding, and care must be taken to avoid double-compression by intermediary caches that occasionally mangle headers.
A Content Delivery Network serves static assets from edge locations close to users, cutting both latency and origin load, and is one of the highest-leverage performance investments for many sites. Beyond edges, the cost of a single connection matters: connection coalescing lets a browser reuse one HTTP/2 connection for multiple domains that share an IP and certificate, and keep-alive avoids repeated TCP setup. DNS itself is not free; the first request to a new domain typically costs 20 to 100 milliseconds, so preconnecting to every critical origin in the document head compounds into noticeable savings.
Caching policies keep performance from drifting as users return. Cache-Control sets freshness and lifetime, while ETag enables conditional revalidation when files do change. Long-lived hash-based filenames such as app.[contenthash].js paired with a Cache-Control directive of public, max-age=31536000, immutable allow the browser to skip revalidation entirely. For assets that change more often, stale-while-revalidate serves the cached version immediately while fetching a fresh copy in the background, balancing freshness against latency. The Vary header should be used sparingly, since each unique value creates a separate cache entry and erodes hit rates.