Prefetch
Prefetch is a resource hint that tells the browser to fetch a resource it will probably need on a later navigation, at low priority behind the current page's own requests, and keep it in the HTTP cache so the next navigation is served locally instead of over the network.
Full Explanation
Prefetch is a resource hint. It tells the browser to fetch something the user will probably need on a later navigation. The browser does this in the background, at low priority. It keeps the result in the HTTP cache. That way, the later request is answered from the device instead of the network. In HTML it is written as <link rel="prefetch" href="/pricing">. The modern form for whole documents is the Speculation Rules API. Beware the word's second meaning. In CDN configuration, "prefetch" usually means the edge server pulling objects from your origin before any client asks for them. Same word, different actor.
Prefetch is not preload. That keyword fetches the current page's own assets at high priority. It is not preconnect or dns-prefetch. Those warm a connection but fetch no content. It is not prerendering either. Prerendering also renders the target page in the background. And it is speculative. The browser may delay it or decline it. If the user never navigates, the bytes are wasted.
How it works
You put the hint on the page that links to the next one:
<link rel="prefetch" href="/pricing">asks the browser to preemptively fetch and cache the target, because the user is likely to need it for a future navigation. The HTML Standard scopes this to "the specified resource or same-site document". MDN is blunter. It says the scope is same-site navigation resources, or subresources used by same-site pages.- The fetch is low priority. MDN describes it as functionally equivalent to fetch() with priority "low", except generally even lower. The spec allows user agents to delay the request, so they can prioritise requests the current document actually needs. That is the whole of the "idle time" story. There is no rule that the browser waits for an idle network. The only rule is that the current page comes first.
- The request is labelled. It carries
Sec-Purpose: prefetch, withSec-Fetch-Dest: empty. A server or CDN can use these to recognise it and treat it differently from a real navigation. - The Accept header matches what the browser sends for a normal navigation. This is how the stored response later matches the real request. Otherwise it would sit in the cache under a different cache key. If a response comes back, it is stored with the request in the HTTP cache on disk.
- On the next navigation the browser reuses that stored copy. The request then costs no round trip. The copy has to still be usable. It is reusable without contacting the server only while it is fresh. A stale copy is normally revalidated first. That revalidation is a round trip again.
For whole documents the Speculation Rules API replaces the link hint. Prefetch rules can sit in a <script type="speculationrules"> block, or in a Speculation-Rules response header. They make supporting browsers download the response body of the referenced pages, but none of their subresources. Those results go into a per-document in-memory cache, not the HTTP cache. They are discarded when the user leaves the current page. It is not a replacement for everything. The Speculation Rules API does not handle subresource prefetches. So <link rel="prefetch"> remains the tool for CSS, fonts and images.
Why it matters for a CDN
Prefetch warms the browser tier of the delivery path, one navigation ahead. When what you prefetched is the next document, that navigation's time to first byte comes from the local copy, not from an RTT out to the edge. When it is a subresource instead, the document's TTFB is unchanged. But the asset is already on the device when the new page asks for it. Either way, the win lands on the second and subsequent pages of a visit, never the first.
The cost side is what CDN operators care about. Every prefetch is a real GET against your edge. It is billed, logged and counted, whether or not the user ever clicks. It is also entirely governed by your caching headers. The Cache-Control you serve decides whether the copy can be stored at all. Its max-age decides how long it stays reusable without a revalidation round trip. A prefetch of an uncacheable response buys nothing.
What CDNs do
- Inject the speculation rules for you. Cloudflare's Speed Brain adds a Speculation-Rules response header. It points at a Cloudflare-hosted rule file. That file asks the browser to consider prefetching future navigations to the site's own paths, with "conservative" eagerness. Speed Brain is available on all plans and enabled by default on Free. Two safeguards matter operationally. Prefetch requests never reach origin servers, and are served only from content already in Cloudflare's cache, with an unsuccessful prefetch answered 503. Routes that invoke a Worker are not prefetched. It requires a Chromium-based browser at version 121 or later.
- Prefetch from origin at the edge. Akamai's Prefetch Objects behaviour makes edge servers retrieve objects embedded in HTML, such as images and scripts. This happens at the same time as the HTML is served, rather than waiting for the browser to ask. It is configured as a pair. Prefetch Objects names the parent pages, and Prefetchable Objects names the children. The behaviour is off by default in Ion and Dynamic Site Accelerator. It works for cacheable and uncacheable content. Akamai recommends pairing it with Tiered Distribution to avoid bursts of requests at the origin. It is not supported with Zone Apex Mapping.
- Predict from history. Akamai's Predictive Prefetching uses historical data to decide which dependent objects a page will need, including objects fetched by JavaScript. It pulls them while the parent request is still in flight to the origin. Its prefetch level is selectable as High, Medium or Low. Akamai warns that a higher level can mean higher midgress cost and heavier origin load.
Watch out for
- no-store and no-cache are not the same block. no-store forbids storing the response at all, so there is nothing to reuse. no-cache does allow storage. But it forbids reuse without revalidating with the origin first. That puts the round trip back. MDN warns generally that certain Cache-Control headers can block prefetching. The precise behaviour is in RFC 9111.
- Cross-site prefetch mostly does not work. Browser cache partitioning makes
<link rel="prefetch">useless for resources meant for a different top-level site. This includes the document itself on a cross-site navigation. Speculation Rules prefetch does support cross-site targets. But for privacy reasons, this only works while the user has no cookies set for the destination site. - Support is narrower than it looks. Chromium and Firefox ship
<link rel="prefetch">. Safari only implements it behind a preference, so treat it as absent there. Speculation Rules is Chromium-only in practice. Chrome and Edge support it from version 109. Firefox does not implement it. Safari has it behind a preference in version 26.2. - A prefetch is not a page view. It must not have side effects. Prefetch traffic arrives before any human decision. So counting it as a visit, or letting it trigger state changes, is a bug. Filter on Sec-Purpose in logs and analytics. Defer anything that should only happen on a real view. A non-success status, for example 503, suppresses the speculative load server-side.
- Speculation Rules prefetches are not durable. They sit in a per-document in-memory cache. They are dropped when the user navigates away from the page that declared them. So they warm one hop, not the whole session.
- Waste is the default failure mode. Prefetch everything, and you pay egress for pages nobody opens, plus origin load for whatever misses cache. The cheaper the prefetch, the broader you can safely go. That is why document prefetch is recommended broadly, while prerender is not.
Best practice
- Choose targets from your own navigation data, not from a hunch. Keep the list to the paths a real share of users actually take next.
- Use Speculation Rules prefetch for documents where it is supported. Keep
<link rel="prefetch">for subresources such as CSS, fonts and images. Feature-detect and fall back rather than shipping both blindly. - Keep
preloadfor the current page's render-critical resources. Browsers deliberately rankprefetchbelowpreload, because the current page matters more than the next one. - Serve what you prefetch as a storable response. Give it a max-age long enough to survive the gap between the hint and the click. Otherwise the browser will revalidate, and you will have bought nothing.
- Make prefetchable URLs safe. No state change on GET, no counters, no sign-out links in the rule set. If a route cannot be made safe, answer prefetch requests with a non-success status.
- Split
Sec-Purpose: prefetchout of your CDN logs and RUM. This way hit ratio, bandwidth and conversion numbers describe real navigations. You can also tell a useful prefetch from a wasted one.
Examples
HTML prefetch hints:
<head>
<!-- Prefetch next page's resources during idle time -->
<link rel="prefetch" href="/pricing">
<link rel="prefetch" href="/static/pricing-hero.avif">
<!-- Compare: preload for CURRENT page (high priority) -->
<link rel="preload" href="/static/hero.avif" as="image">
</head>
Dynamic prefetch based on user behavior:
// Prefetch on hover (high intent signal)
document.querySelectorAll('a[data-prefetch]').forEach(link => {
link.addEventListener('mouseenter', () => {
const prefetchLink = document.createElement('link');
prefetchLink.rel = 'prefetch';
prefetchLink.href = link.href;
document.head.appendChild(prefetchLink);
}, { once: true });
});
// Or use Speculation Rules API (Chrome 109+)
<script type="speculationrules">
{"prefetch": [{"where": {"href_matches": "/pricing/*"}}]}
</script>
Frequently Asked Questions
Prefetch is a resource hint that tells the browser to fetch a resource it will probably need on a later navigation, at low priority behind the current page's own requests, and keep it in the HTTP cache so the next navigation is served locally instead of over the network.
HTML prefetch hints:
<head>
<!-- Prefetch next page's resources during idle time -->
<link rel="prefetch" href="/pricing">
<link rel="prefetch" href="/static/pricing-hero.avif">
<!-- Compare: preload for CURRENT page (high priority) -->
<link rel="preload" href="/static/hero.avif" as="image">
</head>
Dynamic prefetch based on user behavior:
// Prefetch on hover (high intent signal)
document.querySelectorAll('a[data-prefetch]').forEach(link => {
link.addEventListener('mouseenter', () => {
const prefetchLink = document.createElement('link');
prefetchLink.rel = 'prefetch';
prefetchLink.href = link.href;
document.head.appendChild(prefetchLink);
}, { once: true });
});
// Or use Speculation Rules API (Chrome 109+)
<script type="speculationrules">
{"prefetch": [{"where": {"href_matches": "/pricing/*"}}]}
</script>
Related CDN concepts include:
- Preconnect — Preconnect is a resource hint that asks the browser to open a connection (DNS, TCP …