CDN Resource Hints: Preconnect, Prefetch, and Preload Strategies for Edge Delivery
The browser's resource loading pipeline is sequential by nature: parse HTML, discover resources, queue requests, wait for responses. Resource hints let you break this sequence by telling the browser about resources it will need before it discovers them naturally. For CDN-delivered sites, hints are especially powerful because the CDN edge can inject them server-side — via HTTP headers or edge compute transforms — without modifying origin HTML. This article maps each hint type to its CDN use case, quantifies the performance impact, and provides implementation patterns for edge-injected hints.
The Resource Hint Taxonomy
HTML defines five resource hint mechanisms, each operating at a different stage of the resource loading pipeline. Understanding where each hint intervenes is key to deploying them effectively.
dns-prefetch
The lightest-weight hint. <link rel="dns-prefetch" href="//api.example.com"> resolves the hostname's IP address in the background. Cost: one DNS query (~50 bytes). Benefit: 20-120ms saved when the browser eventually requests from that domain. Use it for third-party origins that will probably be contacted: analytics services, ad networks, social media embeds. It is cheap enough to use speculatively.
preconnect
<link rel="preconnect" href="https://cdn.example.com"> completes the full connection setup: DNS, TCP, and TLS. This saves 100-300ms (the sum of all three phases) when the browser later requests a resource from that origin. The cost is higher than dns-prefetch: the browser maintains an idle TCP+TLS connection that consumes memory and a connection slot. Use it for origins you are certain will be contacted within the next 10 seconds — the browser closes idle preconnected sockets after this timeout.
For CDN architectures that use multiple CDN subdomains (e.g., separate domains for static assets, images, and API), preconnect to each subdomain in the HTML head reduces the connection overhead that would otherwise serialize asset loading.
<!-- CDN multi-origin preconnect -->
<link rel="preconnect" href="https://static.cdn.example.com">
<link rel="preconnect" href="https://images.cdn.example.com">
<!-- Third-party preconnect for known dependencies -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Fallback for browsers without preconnect support -->
<link rel="dns-prefetch" href="//static.cdn.example.com">
<link rel="dns-prefetch" href="//images.cdn.example.com">
preload
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin> fetches a specific resource with high priority before the browser would naturally discover it. The as attribute is required — it tells the browser the resource type so it can set the correct priority, send appropriate Accept headers, and apply content security policies. Without as, the browser treats the preload as a low-priority fetch.
Preload is the most impactful hint for Core Web Vitals optimization. Common CDN preload targets:
- LCP image: The image that triggers Largest Contentful Paint is often not discoverable until CSS is parsed and layout computed. Preloading it cuts LCP by the time between HTML parse and natural image discovery (often 200-500ms)
- Web fonts: Fonts are behind a double discovery chain: HTML → CSS → font file. Preloading skips the CSS parsing step
- Critical CSS not in <head>: CSS loaded by JavaScript frameworks or lazy-loading patterns
<!-- Preload the LCP image -->
<link rel="preload" href="/images/hero.webp" as="image"
fetchpriority="high"
type="image/webp">
<!-- Preload critical font -->
<link rel="preload" href="/fonts/brand.woff2" as="font"
type="font/woff2" crossorigin>
<!-- Preload via HTTP header (CDN-injected) -->
<!-- Link: </fonts/brand.woff2>; rel=preload; as=font; crossorigin -->
prefetch
<link rel="prefetch" href="/next-page.html"> fetches a resource at low priority for use in a future navigation. The browser downloads it when idle, storing it in the HTTP cache. When the user clicks a link to the prefetched page, the cached response is served instantly. This is best used on pages where the next navigation is predictable: search results pages (prefetch the first result), multi-step flows (prefetch the next step), and article pages (prefetch the most likely next article).
prerender (Speculation Rules)
The modern replacement for the deprecated <link rel="prerender">, Speculation Rules allow the browser to prerender entire pages in a hidden tab. The browser fetches the HTML, executes JavaScript, renders the DOM, and holds the result. When the user navigates, the prerendered page swaps in instantly — zero visible load time.
<!-- Speculation Rules for prerendering -->
<script type="speculationrules">
{
"prerender": [
{
"where": {
"href_matches": "/articles/*"
},
"eagerness": "moderate"
}
],
"prefetch": [
{
"where": {
"href_matches": "/category/*"
},
"eagerness": "conservative"
}
]
}
</script>
CDN Edge-Injected Hints
The most powerful CDN optimization is injecting resource hints server-side, without requiring origin changes. CDN edge servers can add hints in three ways.
| Metric | Edge Processing | Origin Processing | Improvement |
|---|---|---|---|
| Latency (p50) | 8–15 ms | 120–300 ms | 15–20x faster |
| Cache Hit Ratio | 85–95% | N/A | Reduces origin load |
| TLS Handshake | 1–5 ms (nearby PoP) | 50–150 ms | 10–30x faster |
| Bandwidth Cost | $0.01–0.04/GB | $0.05–0.12/GB | 3–5x cheaper |
| Availability | 99.99% (multi-PoP) | 99.9% (single DC) | 10x fewer outages |
HTTP 103 Early Hints
The edge server sends a 103 informational response containing Link headers while waiting for the origin response. The browser receives these hints and starts preconnecting or preloading immediately, recovering origin latency as preloading time. This is especially effective when the CDN caches the hint configuration but the HTML response is personalized (cache miss at edge).
# CDN edge Early Hints flow
# 1. Client sends request
GET /page HTTP/3
# 2. Edge sends 103 immediately (from cached hints config)
HTTP/3 103 Early Hints
Link: </assets/style.css>; rel=preload; as=style
Link: </fonts/main.woff2>; rel=preload; as=font; crossorigin
Link: <https://images.cdn.example.com>; rel=preconnect
# 3. Edge fetches from origin (or cache)...
# 4. Edge sends final response
HTTP/3 200 OK
Content-Type: text/html
<html>...</html>
HTML Injection at Edge
For CDNs that support edge compute or HTML transforms, hints can be injected directly into the HTML <head>. This approach is more flexible than HTTP headers because it can use the Speculation Rules API and include responsive preload variants with media attributes.
# Edge worker hint injection (pseudocode)
async function injectHints(request, response) {
const html = await response.text();
const hints = getHintsForPage(request.url);
const hintTags = hints.map(h => {
if (h.type === 'preload') {
return `';
}
if (h.type === 'preconnect') {
return ``;
}
return '';
}).join('\n');
// Insert after tag
const modified = html.replace(
'',
`\n${hintTags}`
);
return new Response(modified, response);
}
Link Header Injection
The simplest approach: the CDN adds Link headers to every HTML response. This works with any CDN that supports response header manipulation and does not require edge compute. The browser interprets Link headers with rel=preload identically to HTML <link rel="preload"> tags.
# Nginx CDN edge configuration
server {
location ~* \.html$ {
# Add resource hints via Link headers
add_header Link "; rel=preload; as=style" always;
add_header Link "; rel=preload; as=font; crossorigin" always;
add_header Link "; rel=preconnect" always;
proxy_pass http://origin;
}
}
Measuring Hint Effectiveness
Resource hints must be measured in production with real users. Lab tests (Lighthouse, WebPageTest) show the theoretical benefit but miss the variability of real network conditions. Use the Resource Timing API to measure actual impact:
# JavaScript: Measure hint effectiveness
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.initiatorType === 'link') {
const dnsTime = entry.domainLookupEnd - entry.domainLookupStart;
const connectTime = entry.connectEnd - entry.connectStart;
const fetchTime = entry.responseEnd - entry.fetchStart;
// dnsTime === 0 means dns-prefetch worked
// connectTime === 0 means preconnect worked
// fetchTime very low means preload cache hit
analytics.send('resource_timing', {
name: entry.name,
dns: dnsTime,
connect: connectTime,
total: fetchTime,
transferSize: entry.transferSize,
});
}
}
});
observer.observe({ type: 'resource', buffered: true });
Common Pitfalls
Preloading too many resources: If everything is preloaded, nothing is prioritized. Limit preloads to 3-5 truly critical resources. Each preload competes for bandwidth with other in-flight requests during the critical rendering path.
Missing the crossorigin attribute: Font preloads require crossorigin even when the font is same-origin. Without it, the browser makes two requests: one from the preload (without CORS) and one from the CSS @font-face rule (with CORS). The preloaded response is discarded.
Stale hints after redesigns: When CDN edge servers cache hint configurations, a site redesign that changes resource URLs leaves the hints pointing to old files. The browser preloads resources that no longer exist while the actual critical resources load without hints. Implement cache invalidation for hint configurations alongside content deployments.
Preconnecting to the same origin: If your site is served through a single CDN domain, preconnecting to that domain is pointless — the browser already has a connection from loading the HTML document. Preconnect only helps for additional origins (font CDNs, image subdomains, third-party APIs).
Resource hints are the bridge between edge caching and optimal rendering. The CDN serves resources instantly from cache, and hints ensure the browser knows to request them at the right time. Combined with HTTP/3 stream prioritization and edge latency optimization, resource hints close the gap between "resource available at the CDN edge" and "resource delivered into the rendering pipeline at the moment it's needed."