Web Performance Optimization
19 min read

Web Performance Infrastructure: DNS, CDN, Caching, and Edge

Infrastructure optimization addresses the foundation of web performance—the layers between a user’s request and your application’s response. This article covers DNS as a performance lever, HTTP/3 and QUIC for eliminating protocol-level bottlenecks, CDN and edge computing for geographic proximity, compression strategies for payload reduction, and caching patterns that can reduce Time to First Byte (TTFB) by 85-95% while offloading 80%+ of traffic from origin servers.

Performance Targets

Infrastructure Performance Layers

Connection Layer

DNS, HTTP/3, TLS 1.3

Edge Network

CDN, Edge Computing

Payload Optimization

Compression, Minification

Origin Infrastructure

Load Balancing, Caching, DB

TTFB: <100ms

Edge Offload: >80%

Cache Hit: >90%

Infrastructure optimization layers: connection, edge, payload, and origin working together for sub-100ms TTFB

Infrastructure performance follows a layered model where each layer multiplies the impact of the one below it:

Optimization Strategy

Eliminate RTTs

Move closer to user

Reduce bytes

Cache aggressively

Request Lifecycle

DNS

(50-300ms)

Connection

(100-200ms)

Edge

(5-20ms)

Origin

(50-500ms)

Core mental model: Every request traverses DNS → Connection → Edge → Origin. Optimization means either eliminating layers entirely (edge caching bypasses origin), reducing round trips within layers (HTTP/3 merges crypto and transport handshakes), or moving computation closer to the user (edge functions).

Key trade-offs to understand:

OptimizationWhat it buysWhat it costs
HTTP/3 (QUIC over UDP)Eliminates TCP head-of-line blocking, 0-RTT resumptionUDP may be blocked/throttled, requires infrastructure changes
Edge computingSub-10ms latency to users, origin offloadLimited runtime (no filesystem, constrained memory), vendor lock-in
Aggressive caching90%+ origin offload, instant responsesCache invalidation complexity, stale data risk
Pre-compression (Brotli 11)15-27% smaller than gzipBuild time cost, storage for multiple variants

Performance targets (2025 benchmarks):

  • DNS: <20ms excellent, <50ms acceptable
  • Connection (HTTP/3): <100ms, with 0-RTT resumption for return visitors
  • TTFB: <100ms excellent, <200ms good
  • Origin offload: >80% of bytes from edge

The initial moments of a user’s interaction with a website are defined by the speed and efficiency of the network connection. Latency introduced during DNS lookup, protocol negotiation, and security handshake can significantly delay TTFB.

Modern DNS has evolved from a simple directory into a sophisticated signaling mechanism through SVCB and HTTPS record types (RFC 9460, published November 2023).

Why HTTPS records exist: Before RFC 9460, browsers discovered HTTP/3 support only after connecting via HTTP/2, receiving an Alt-Svc header, and then upgrading on subsequent requests. This added 1-2 RTTs to the first HTTP/3 connection. HTTPS records move protocol negotiation into DNS, enabling direct HTTP/3 connections on the first request.

HTTPS Record Benefits:

  • alpn parameter: Advertises HTTP/3 support (alpn="h3"), allowing browsers to skip protocol upgrade negotiation
  • ipv4hint/ipv6hint: Provides IP addresses, potentially saving additional DNS lookups
  • Saves 100-300ms: By enabling direct HTTP/3 connection attempts

Adoption (2025): ~15% of top 1M domains have HTTPS records, with Cloudflare’s automatic deployment driving ~80% of that adoption. Browser support: Chrome 96+, Firefox 78+ (DoH only), Safari 14+ (most complete implementation).

; HTTPS record enabling HTTP/3 discovery
example.com. 300 IN HTTPS 1 . alpn="h3,h2" port="443" ipv4hint="192.0.2.1"
; SVCB record for service binding
_service.example.com. 300 IN SVCB 1 svc.example.net. alpn="h3" port="8443"

Measurement:

dns-timing.js
const measureDNSTiming = () => {
const navigation = performance.getEntriesByType("navigation")[0]
const dnsTime = navigation.domainLookupEnd - navigation.domainLookupStart
return {
timing: dnsTime,
status: dnsTime < 20 ? "excellent" : dnsTime < 50 ? "good" : "needs-improvement",
}
}

HTTP/3 (RFC 9114, June 2022) abandons TCP for QUIC (RFC 9000), providing transformative benefits (HTTP/3 Explained):

Why QUIC exists: TCP’s design predates the modern web. Its head-of-line blocking (a single lost packet blocks all streams), 2-RTT handshake, and IP-bound connections create latency that can’t be fixed at the application layer. QUIC redesigns the transport layer with web workloads in mind.

Elimination of Head-of-Line Blocking: QUIC implements streams as first-class citizens. Packet loss in one stream doesn’t impact others—critical for complex web pages loading dozens of parallel resources. Research shows HTTP/3 can achieve up to 81.5% improvement in extreme loss scenarios.

Faster Connection Establishment: QUIC integrates cryptographic and transport handshakes into a single RTT. Combined with 0-RTT resumption for returning visitors, this can eliminate handshake latency entirely.

Connection Migration: Uses Connection ID (CID) instead of IP/port tuple, allowing seamless network switching (Wi-Fi to cellular) without reconnection. This addresses a pain point that TCP fundamentally cannot solve.

Adoption (2025): 37% of websites globally support HTTP/3 (W3Techs), with 21% of actual requests using HTTP/3 (Cloudflare Radar). Browser support is mature: Chrome 87+, Firefox 88+, Safari 16+ (enabled by default September 2024), Edge 87+.

Yes

No

Browser Request

DNS Lookup

HTTPS Record Check

HTTP/3 Supported?

Direct QUIC Connection

TCP + TLS Handshake

HTTP/3 Streams

HTTP/2 Multiplexing

Independent Stream Processing

TCP-Level HOL Blocking Risk

Faster Page Load

Potential Delays

Performance Impact (2025 benchmarks):

ScenarioHTTP/3 vs HTTP/2Notes
TTFB (average)12.4% faster176ms vs 201ms
High packet loss (15%)55% fasterQUIC’s stream independence
Extreme loss scenarios81-88% fasterTCP completely stalls
Small pages (15KB)~3% fasterMarginal gain
Large pages (1MB)HTTP/2 slightly fasterCongestion algorithm differences

Why HTTP/3 doesn’t always win: Current HTTP/3 implementations often use CUBIC congestion control while HTTP/2 uses BBR. Cloudflare’s research shows HTTP/3 trails by 1-4% on average in stable network conditions due to these algorithm differences, not protocol overhead.

TLS 1.3 (RFC 8446, August 2018; revision draft-ietf-tls-rfc8446bis in AUTH48 as of September 2025) was redesigned with performance as a core feature.

Why TLS 1.3 is faster: TLS 1.2 required 2 RTTs because the client and server exchanged multiple messages sequentially (ClientHello → ServerHello → Certificate → KeyExchange → Finished). TLS 1.3 merges these into a single flight by using ephemeral Diffie-Hellman exclusively and sending encrypted data immediately after the first round trip.

1-RTT Handshake: Streamlined negotiation requires only a single round trip (vs 2 RTT for TLS 1.2), reducing latency by 30-50%.

0-RTT Resumption: Returning visitors can send encrypted data in the first packet, eliminating handshake latency for ~40% of connections that are resumptions.

0-RTT Security Trade-off: 0-RTT data is vulnerable to replay attacks—an attacker can capture and resend the encrypted request. Mitigations: use 0-RTT only for idempotent requests (GET), implement server-side replay detection, or disable 0-RTT for sensitive operations. Cloudflare keeps 0-RTT disabled by default for Business/Enterprise zones due to this risk.

Adoption (2025): 62-70% of websites support TLS 1.3 (SSL Labs). Browser support: Chrome 70+, Firefox 63+, Safari 12.2+, Edge 79+. Post-quantum cryptography with TLS 1.3 is emerging: 43% of Cloudflare connections use hybrid post-quantum key exchange (September 2025).

TLS 1.2

2 RTT Handshake

TLS 1.3

1 RTT Handshake

0-RTT Resumption

0 RTT for Return Visits

~200ms Setup Time

~100ms Setup Time

~0ms Setup Time

OptimizationBenefitsTrade-offsAdoption (2025)
SVCB/HTTPS RecordsFaster protocol discovery, skip Alt-Svc upgradeDNS infrastructure changes, mixed browser implementation quality~15% of top 1M domains
HTTP/3 AdoptionNo TCP HOL blocking, 0-RTT, connection migrationUDP may be blocked/throttled, infrastructure changes37% of websites
TLS 1.3 Migration1-RTT handshake (50% faster than TLS 1.2)Certificate/infrastructure updates62-70% of websites
0-RTT ResumptionZero handshake latency for return visitorsReplay attack vulnerability, requires idempotent operationsSelectively enabled

By bringing content and computation closer to end-users, edge networks dramatically reduce latency, absorb traffic spikes, and improve overall application performance.

A CDN’s primary goal is to reduce latency by serving content from geographically proximate Points of Presence (PoPs).

Why CDNs work: Speed of light limits latency to ~1ms per 200km of fiber. A user in Sydney connecting to a San Francisco origin faces ~150ms minimum latency. A CDN PoP in Sydney reduces this to <10ms for cached content.

Core Principles:

  • Geographic Distribution: Minimizes physical distance, reducing round-trip time
  • Static Asset Caching: Delivers images, CSS, JS from edge cache—orders of magnitude faster than origin
  • DDoS Protection: Distributed infrastructure absorbs attacks

Origin Offload vs Cache-Hit Ratio:

Cache-hit ratio treats all requests equally. Origin offload measures percentage of bytes from cache—a more meaningful Key Performance Indicator (KPI) that reflects actual infrastructure savings. A 95% cache-hit ratio with 5% of requests being large API responses could mean only 50% origin offload by bytes.

cdn-strategy.js
const cdnStrategy = {
static: {
maxAge: 31536000, // 1 year
types: ["images", "fonts", "css", "js"],
headers: {
"Cache-Control": "public, max-age=31536000, immutable",
},
},
dynamic: {
maxAge: 300, // 5 minutes
types: ["api", "html"],
headers: {
"Cache-Control": "public, max-age=300, stale-while-revalidate=60",
},
},
micro: {
maxAge: 5, // 5 seconds
types: ["inventory", "pricing", "news"],
headers: {
"Cache-Control": "public, max-age=5, stale-while-revalidate=30",
},
},
}

Edge computing extends CDNs from content delivery to distributed application platforms.

Why edge computing matters: Traditional CDNs cache static content but still require origin round-trips for any dynamic logic. Edge computing runs code at the PoP, enabling personalization, authentication, and business logic at <10ms latency vs 100-300ms for origin requests.

Platform landscape (2025):

PlatformRuntimeCold StartKey Strength
Cloudflare WorkersV8 isolates~5ms (effectively zero)99.99% warm request rate
Vercel Edge FunctionsV8 isolates9x faster than LambdaFluid Compute pricing
Netlify Edge FunctionsDenoFaster than Node.jsNetlify ecosystem integration
Fastly ComputeWebAssemblyMicrosecondsMulti-language support
AWS Lambda@EdgeNode.js/PythonSecondsAWS ecosystem

Key Use Cases:

  • Dynamic Content Acceleration: Perform personalization logic closer to users
  • A/B Testing: Execute variant selection at edge without origin round-trip
  • Edge Authentication: Block invalid requests immediately, protecting origin
edge-worker.js
3 collapsed lines
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const url = new URL(request.url)
// A/B testing at the edge
if (url.pathname === "/homepage") {
const variant = getABTestVariant(request)
const content = await generatePersonalizedContent(request, variant)
return new Response(content, {
headers: {
"content-type": "text/html",
"cache-control": "public, max-age=300",
"x-variant": variant,
},
})
}
// Geo-routing and localized caching
const country = request.headers.get("cf-ipcountry")
const localizedContent = await getLocalizedContent(country)
return new Response(localizedContent, {
headers: {
"content-type": "text/html",
"cache-control": "public, max-age=600",
},
})
}

Architecture Shift: The CDN evolves from cache to application perimeter. The question changes from “How do we make the origin faster?” to “How much can we prevent from ever hitting the origin?”

Edge computing limitations: No filesystem access, no TCP/UDP sockets (except Deno Deploy), constrained memory (2MB-3GB depending on platform), no dynamic code execution (eval/new Function), limited execution time (1ms-30s). These constraints exist because edge runtimes prioritize isolation and fast cold starts over flexibility.

The choice of algorithm involves a trade-off between compression ratio and speed, requiring different strategies for static and dynamic content.

Why multiple algorithms exist: Gzip (1992) optimized for the hardware of its era. Brotli (2015) was designed by Google specifically for web content, achieving 15-27% better compression than gzip by using a pre-defined dictionary of common web strings. Zstandard (2016) from Facebook prioritizes compression speed while matching Brotli’s ratios.

Static Content (Pre-compression): Use the most effective algorithm at highest quality since compression time doesn’t affect users:

  • Brotli level 11 produces smallest files (15-27% smaller than gzip)
  • Pre-compress during build: .js.br, .css.br
  • Server serves appropriate pre-compressed file based on Accept-Encoding

Dynamic Content (On-the-fly): Compression happens in real-time, so speed matters (compression benchmarks):

  • Brotli level 4-5: Better than gzip at similar speed
  • Zstandard level 3-12: 42% faster than Brotli at similar ratios

Edge Compression: Offload compression to CDN to free origin CPU. CDNs can cache compressed variants and serve the appropriate one based on client support.

Browser support (2025): Brotli has 96% global support (all modern browsers). Zstandard has 76% support (Chrome 123+, Firefox 126+, Edge 123+; Safari can decompress but doesn’t request it).

AlgorithmStaticDynamicBrowser Support (2025)Trade-off
GzipLevel 6-9Level 699%+Universal fallback, ~30% worse than Brotli
BrotliLevel 11Level 4-596%Best ratio, slow at high levels
ZstandardLevel 19Level 3-1276%42% faster compression than Brotli, similar ratio

CDN adoption (2025): CDN servers use Brotli (46%), gzip (42%), Zstandard (12%). Origin servers lag behind: gzip (61%), Brotli (39%), Zstandard minimal. ~30% of sites still use gzip level 1, leaving 25-30% compression gains on the table.

Nginx Configuration:

http {
# Brotli compression
brotli on;
brotli_comp_level 6;
brotli_types
application/javascript
application/json
text/css
text/html;
# Gzip fallback
gzip on;
gzip_vary on;
gzip_types
application/javascript
text/css
text/html;
# Static pre-compressed files
gzip_static on;
brotli_static on;
}

Why algorithm choice matters: The wrong algorithm can create hot spots (overloaded servers while others idle) or break session state. The right choice depends on your traffic pattern and statefulness requirements.

Static Algorithms:

  • Round Robin: Simple sequential distribution; best for homogeneous servers with stateless workloads
  • Weighted Round Robin: Assigns weight based on server capacity; use when servers have different specs

Dynamic Algorithms:

  • Least Connections: Routes to server with fewest active connections; better for long-lived connections (WebSocket, streaming)
  • Least Response Time: Routes to fastest-responding server; best for latency optimization when backend performance varies

Session Persistence:

  • Source IP Hash: Maps client IP to specific server for session continuity; breaks when users are behind NAT or proxies
  • Cookie-based: More reliable than IP hash but requires cookie support

An in-memory caching layer (Redis, Memcached) stores expensive query results, serving subsequent requests from RAM (Random Access Memory).

Why in-memory caching works: RAM access is ~100,000x faster than SSD (~100ns vs ~10ms). For read-heavy workloads, caching database query results in RAM can reduce p99 latency from 100ms to <1ms.

Redis vs Memcached:

AspectMemcachedRedis
Data modelKey-value onlyStrings, hashes, lists, sets, sorted sets
ThreadingMulti-threadedSingle-threaded (+ I/O threads in Redis 6+)
PersistenceNone (volatile)RDB snapshots, AOF logging
ReplicationNone built-inPrimary-replica, Redis Cluster
Use caseSimple caching, maximum throughputComplex caching, data structures, pub/sub

When to use Memcached: Pure caching with simple key-value access, maximum multi-core utilization, no persistence requirements.

When to use Redis: Need data structures (leaderboards with sorted sets, rate limiting with atomic increments), persistence, replication, or pub/sub.

cache-helper.js
const getCachedData = async (key, fetchFunction, ttl = 3600) => {
try {
const cached = await redis.get(key)
if (cached) {
return JSON.parse(cached)
}
const data = await fetchFunction()
await redis.setex(key, ttl, JSON.stringify(data))
return data
} catch (error) {
return await fetchFunction()
}
}

Why database optimization matters: Database queries are often the largest contributor to TTFB. A single unindexed query can take 100ms+ while the same query with proper indexing takes <1ms.

Query Optimization:

  • Never use SELECT *; request only needed columns (reduces I/O and network transfer)
  • Use EXPLAIN (PostgreSQL) or EXPLAIN ANALYZE to inspect execution plans
  • Ensure JOIN columns are indexed; missing indexes on JOIN columns cause full table scans

Strategic Indexing:

  • Index columns in WHERE, JOIN, ORDER BY clauses
  • Avoid over-indexing: each index slows writes and consumes storage
  • Consider partial indexes for filtered queries (e.g., WHERE status = 'active')

Read Replicas:

  • Direct writes to primary, distribute reads across replicas
  • Replication lag trade-off: replicas may be milliseconds to seconds behind primary
  • Use for read-heavy workloads where eventual consistency is acceptable

Connection Pooling:

  • Maintain pool of connections for reuse; creating new connections takes 10-50ms
  • Size pool appropriately: too small causes queueing, too large wastes memory
  • Tools: PgBouncer (PostgreSQL), ProxySQL (MySQL)

Renders pages as static HTML by default, hydrating only interactive components (islands) on demand (Astro Islands).

Why islands exist: Traditional Single Page Applications (SPAs) ship the entire application as JavaScript, even for mostly-static content. Islands architecture recognizes that most content doesn’t need interactivity—only specific “islands” (search boxes, comment sections, shopping carts) need JavaScript.

Core Principles:

  • Static by Default: No JavaScript required for initial display
  • Selective Hydration: Interactive components hydrate based on triggers (client:load, client:visible, client:idle)
  • Progressive Enhancement: Functionality adds incrementally; content is accessible without JavaScript
index.astro
---
const posts = await getPosts()
---
<html>
<body>
<!-- Static HTML - no JavaScript -->
<main>
{
posts.map((post) => (
<article>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))
}
</main>
<!-- Interactive islands - hydrated on demand -->
<SearchComponent client:load />
<NewsletterSignup client:visible />
<CommentsSection client:idle />
</body>
</html>

Performance Benefits:

  • Initial bundle size: 50-80% reduction
  • Near-instant TTI for static content
  • Full SSR for SEO

Zero-hydration approach: serializes execution state into HTML and resumes exactly where server left off on user interaction (Qwik Resumability).

Why resumability matters: Hydration requires downloading, parsing, and executing JavaScript to rebuild the component tree—even for components the user never interacts with. Resumability skips this entirely by serializing the application state into the HTML, loading component code only when the user interacts with that specific component.

Key Advantages:

  • Zero JavaScript execution on initial load
  • Instant interactivity on first interaction (no hydration delay)
  • Time to Interactive (TTI) doesn’t degrade with application size

Trade-off: Serializing state increases HTML size. Works best for content-heavy sites with occasional interactivity; less suited for highly interactive applications where most components will be used.

Creates specialized backend services that aggregate data from multiple microservices into optimized responses.

Why BFF exists: In microservices architectures, a single page may require data from 5-10 services. Having the frontend make all these calls creates: (1) waterfall latency as calls often depend on each other, (2) over-fetching as each service returns its full response, (3) complexity in handling partial failures. A BFF aggregates these calls server-side, returning a single optimized payload.

Performance Impact:

MetricWithout BFFWith BFFImprovement
Payload Size150-200KB80-120KB30-50% reduction
API Requests5-8 requests1-2 requests60-80% reduction
Response Time800-1200ms200-400ms60-75% faster
Cache Hit Rate30-40%70-85%40-45% improvement
product-bff.js
class ProductPageBFF {
async getProductPageData(productId, userId) {
const [product, reviews, inventory, recommendations] = await Promise.all([
this.productService.getProduct(productId),
this.reviewService.getReviews(productId),
this.inventoryService.getStock(productId),
this.recommendationService.getRecommendations(productId, userId),
])
return {
product: this.transformProduct(product),
reviews: this.optimizeReviews(reviews),
availability: this.formatAvailability(inventory),
recommendations: this.filterRecommendations(recommendations),
}
}
}

Differentiate network paths for client-side and server-side data fetching.

Why private routing matters: Client-side API calls traverse the public internet (100-300ms latency, egress costs, exposure to attacks). Server-side calls within a Virtual Private Cloud (VPC) use internal networking (5-20ms latency, no egress costs, isolated from internet).

Fetching ContextNetwork PathPerformanceSecurity
Client-SidePublic Internet → CDN → Origin100-300msStandard
Server-SidePrivate VPC → Internal Network5-20msEnhanced

Implementation:

api-client.js
class APIClient {
constructor() {
this.publicUrl = process.env.NEXT_PUBLIC_API_URL
this.privateUrl = process.env.API_URL_PRIVATE
}
// Client-side API calls (public internet)
async clientFetch(endpoint, options = {}) {
return fetch(`${this.publicUrl}${endpoint}`, options)
}
// Server-side API calls (private VPC)
async serverFetch(endpoint, options = {}) {
return fetch(`${this.privateUrl}${endpoint}`, {
...options,
headers: {
"X-Internal-Request": "true",
...options.headers,
},
})
}
}

Performance Impact:

  • TTFB: 85-95% faster (5-20ms vs 150-300ms)
  • Cost: 60-80% savings on egress
  • Security: VPC isolation
service-worker.js
4 collapsed lines
import { registerRoute } from "workbox-routing"
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from "workbox-strategies"
import { ExpirationPlugin } from "workbox-expiration"
// Cache-first for static assets
registerRoute(
({ request }) => request.destination === "image" || request.destination === "font",
new CacheFirst({
cacheName: "static-assets",
plugins: [
new ExpirationPlugin({
maxEntries: 100,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
}),
],
}),
)
// Stale-while-revalidate for CSS/JS
registerRoute(
({ request }) => request.destination === "script" || request.destination === "style",
new StaleWhileRevalidate({
cacheName: "bundles",
}),
)
// Network-first for API responses
registerRoute(
({ url }) => url.pathname.startsWith("/api/"),
new NetworkFirst({
cacheName: "api-cache",
networkTimeoutSeconds: 3,
plugins: [
new ExpirationPlugin({
maxEntries: 50,
maxAgeSeconds: 5 * 60,
}),
],
}),
)
data-cache.js
class DataCache {
async cacheApiResponse(url, data, ttl = 300000) {
const transaction = this.db.transaction(["apiResponses"], "readwrite")
const store = transaction.objectStore("apiResponses")
await store.put({
url,
data,
timestamp: Date.now(),
ttl,
})
}
async getCachedApiResponse(url) {
const result = await this.db.get("apiResponses", url)
if (result && Date.now() - result.timestamp < result.ttl) {
return result.data
}
return null
}
}
rum-monitor.js
14 collapsed lines
class RUMBudgetMonitor {
constructor() {
this.budgets = {
lcp: 2500,
fcp: 1800,
inp: 200,
cls: 0.1,
ttfb: 600,
}
this.violations = []
this.initMonitoring()
}
initMonitoring() {
if ("PerformanceObserver" in window) {
// LCP monitoring
const lcpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries()
const lastEntry = entries[entries.length - 1]
if (lastEntry.startTime > this.budgets.lcp) {
this.recordViolation("LCP", lastEntry.startTime, this.budgets.lcp)
}
})
lcpObserver.observe({ entryTypes: ["largest-contentful-paint"] })
// INP monitoring
const inpObserver = new PerformanceObserver((list) => {
const entries = list.getEntries()
const maxInp = Math.max(...entries.map((entry) => entry.value))
if (maxInp > this.budgets.inp) {
this.recordViolation("INP", maxInp, this.budgets.inp)
}
})
inpObserver.observe({ entryTypes: ["interaction"] })
// CLS monitoring
const clsObserver = new PerformanceObserver((list) => {
let clsValue = 0
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
clsValue += entry.value
}
11 collapsed lines
}
if (clsValue > this.budgets.cls) {
this.recordViolation("CLS", clsValue, this.budgets.cls)
}
})
clsObserver.observe({ entryTypes: ["layout-shift"] })
}
}
recordViolation(metric, actual, budget) {
this.violations.push({
metric,
actual,
budget,
timestamp: Date.now(),
url: window.location.href,
})
this.sendViolation({ metric, actual, budget })
}
}

Lighthouse CI:

.github/workflows/performance.yml
name: Performance Audit
on: [pull_request, push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
configPath: "./lighthouserc.json"
uploadArtifacts: true

Bundle Size Monitoring:

.size-limit.js
module.exports = [
{
name: "Main Bundle",
path: "dist/main.js",
limit: "150 KB",
gzip: true,
},
{
name: "CSS Bundle",
path: "dist/styles.css",
limit: "50 KB",
gzip: true,
},
]
  • Configure HTTPS DNS records with alpn="h3"
  • Enable HTTP/3 on CDN/origin
  • Upgrade to TLS 1.3 with 0-RTT resumption
  • Implement DNS prefetching for third-party domains
  • Configure CDN with appropriate TTLs
  • Implement edge functions for dynamic personalization
  • Set up micro-caching for semi-dynamic content
  • Monitor origin offload percentage
  • Pre-compress static assets with Brotli level 11
  • Configure dynamic compression at level 4-5
  • Offload compression to CDN where possible
  • Verify compression headers in responses
  • Implement Redis/Memcached caching layer
  • Configure read replicas for databases
  • Set up connection pooling
  • Optimize database queries and indexes
  • Evaluate Islands Architecture for content sites
  • Implement BFF pattern for microservices aggregation
  • Configure private VPC routing for server-side fetches
  • Set up multi-layer caching (SW + IndexedDB + CDN)
  • Deploy RUM for real-user metrics
  • Integrate Lighthouse CI in pipelines
  • Set up performance budgets with size-limit
  • Configure automated alerting
  • Understanding of HTTP request/response lifecycle
  • Familiarity with DNS, TCP/IP, and TLS concepts
  • Basic knowledge of caching principles (TTL, cache invalidation)
  • Experience with CDN configuration
  • TTFB (Time to First Byte): Time from request initiation to receiving the first byte of response
  • RTT (Round-Trip Time): Time for a packet to travel to a destination and back
  • PoP (Point of Presence): CDN edge location that serves content to nearby users
  • QUIC: UDP-based transport protocol designed by Google, now standardized as RFC 9000
  • HOL Blocking (Head-of-Line Blocking): When a single slow/lost packet delays all subsequent packets
  • 0-RTT: Zero round-trip time resumption, allowing encrypted data in the first packet for returning connections
  • BFF (Backend for Frontend): A specialized backend service that aggregates data for a specific frontend client
  • VPC (Virtual Private Cloud): Isolated cloud network with private IP addressing
  • Connection layer: HTTPS DNS records enable direct HTTP/3 connections (saving 100-300ms), HTTP/3 eliminates TCP head-of-line blocking (55-88% faster under packet loss), TLS 1.3 reduces handshake to 1-RTT (0-RTT for return visitors)
  • Edge network: CDNs reduce latency via geographic proximity; measure origin offload (bytes) not just cache-hit ratio; edge computing runs code at PoPs with <10ms latency
  • Compression: Pre-compress static assets with Brotli 11 (15-27% smaller than gzip); use Brotli 4-5 or Zstandard for dynamic content; 96% browser support for Brotli, 76% for Zstandard
  • Origin infrastructure: In-memory caching (Redis/Memcached) reduces database load; read replicas scale read capacity; connection pooling eliminates connection overhead
  • Architectural patterns: Islands architecture reduces JavaScript by 50-80%; BFF pattern cuts payload 30-50% and requests 60-80%; private VPC routing improves TTFB by 85-95%
  • Performance targets: TTFB <100ms excellent, DNS <20ms excellent, origin offload >80%

Specifications (Primary Sources)

Official Documentation

Core Maintainer Content

Industry Expert Blogs

Read more