Claude Fable 5.1 & GPT-6 Astra packages are live

Prefetching

Free

Loading things before they are needed — resource hints, prefetch on intent, speculation rules, and not wasting a user's bandwidth or battery.

183 lines7.4 KB Deepseek Performance
targetModels
DeepSeek V4DeepSeek V3.2DeepSeek R1DeepSeek V3 FamilyFuture DeepSeek Models
name
prefetching
category
Performance
description
Loading things before they are needed — resource hints, prefetch on intent, speculation rules, and not wasting a user's bandwidth or battery.
license
MIT
author
Agent.md maintainers
last-verified
reviewed-by
unreviewed
<!-- Generated from models/_canonical by scripts/build-model-variants.js. Edit the canonical source, not this file. Behavioural profile for DeepSeek: scripts/model-profiles.json -->

#Task boundary

  1. Implement exactly the task as stated. Do not add abstractions, options, config, or files the task did not name.
  2. Comments, identifiers, commit messages and log strings are English only.
  3. Stop when the checklist at the end passes. Do not refactor or "improve" surrounding code.
  4. Every checklist item below is backed by an assertion in a test or by pasted command output, never by a sentence.

#Purpose

Rules for fetching resources before the user asks. Done well, a navigation feels instant. Done badly, prefetching competes with the resources that are actually blocking the current page, and costs users money on metered connections.

The governing question for every hint: does this compete with something the user needs right now? If yes, it is a regression, not an optimisation.


#The hints, and what each actually does

HintDoesCost if wrong
dns-prefetchResolves DNS onlyNegligible
preconnectDNS + TCP + TLSAn idle connection; limited slots
preloadFetches now, high priorityCompetes with render-blocking work
modulepreloadFetches and parses an ES moduleSame
prefetchFetches at lowest priority for a future navigationBandwidth
prerender (speculation rules)Renders the whole page in the backgroundCPU, memory, bandwidth
html
<link rel="preconnect" href="https://cdn.example.com" crossorigin />
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />
<link rel="prefetch" href="/checkout" as="document" />

Two frequent mistakes:

  1. preload without as — the browser cannot set a priority or reuse the response, and the resource is fetched twice.
  2. preload for fonts without crossorigin — fonts fetch in CORS mode, so the preload does not match and downloads again.

Preload only what blocks the first render: typically one font and the LCP image. Everything else competes with them. → Performance/fonts


#Prefetch on intent, not on load

Prefetching every link on a page wastes bandwidth on the majority nobody clicks. Use signals that precede the click:

tsx
<Link href="/reports"
      onMouseEnter={() => router.prefetch("/reports")}
      onFocus={() => router.prefetch("/reports")} />
SignalLead timeAccuracy
Viewport entrySecondsLow — most visible links are not clicked
Hover200–300 msHigh
Focus (keyboard)SimilarHigh
pointerdown~80 msVery high
Known flow step (cart → checkout)LongVery high

Hover plus focus is the default: enough lead time to matter, high enough accuracy not to be wasteful, and it covers keyboard users.

For known funnels, prefetch the next step as soon as the user enters the current one — the checkout bundle should already be there when they finish the cart.


#Speculation rules

html
<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/checkout" },
    "eagerness": "moderate"
  }],
  "prefetch": [{
    "where": { "href_matches": "/*" },
    "eagerness": "conservative"
  }]
}
</script>

eagerness controls the trigger: conservative on pointer-down, moderate on hover, eager immediately. Start conservative and raise it only where the conversion is genuinely predictable.

Prerendering runs the page, including its JavaScript. Consequences:

  1. Analytics will record a page view for a page nobody saw. Gate on the Page Visibility API or document.prerendering.
  2. Any side effect — a POST, a counter increment, a "mark as read" — executes. Never prerender a page that mutates state on load.
  3. It costs real CPU and memory on the user's device. Prerender one likely destination, not ten.

#Respect the user's constraints

ts
const c = (navigator as any).connection;
if (c?.saveData || /2g/.test(c?.effectiveType ?? "")) return;   // do not prefetch
  1. Honour Save-Data and prefers-reduced-data. Prefetching on a metered connection spends the user's money on something they may never use.
  2. Skip prefetching on slow connections — the bandwidth is needed for the current page.
  3. Consider battery: speculative work on a low battery is a poor trade.
  4. Prefetched responses obey Cache-Control. A resource marked no-store is fetched and discarded — pure waste. Check the headers on anything you prefetch.
  5. Never prefetch authenticated or personalised URLs speculatively — the response may be cached, logged or attributed to the wrong session, and it creates load nobody asked for. → Performance/caching

#Anti-patterns

Anti-patternWhy it failsFix
preload without asNo priority; fetched twiceAlways specify as
Font preload without crossoriginDownloaded twiceAdd crossorigin
Preloading many resourcesCompetes with render-blocking workOne font, the LCP image
preload used for future navigationsWrong hint; high priority nowprefetch
preconnect to many originsIdle connections; limited slotsOnly definite origins
Prefetching every link on loadBandwidth for links nobody clicksPrefetch on intent
Viewport-based prefetch on a link-dense pageDozens of wasted requestsHover/focus, or conservative eagerness
eagerness: eager by defaultSpeculative cost for most usersStart conservative
Prerendering a page with side effectsPOSTs and counters fire unseenNever prerender mutating pages
Prerender without visibility gatingPhantom analytics page viewsdocument.prerendering
Prerendering many candidatesCPU and memory on the user's deviceOne likely destination
Ignoring Save-DataSpends a metered user's moneyCheck and skip
Prefetching no-store responsesFetched and discardedCheck cache headers
Prefetching authenticated URLsWrong-session caching; unnecessary loadNever speculatively
Prefetching without measuringMay be pure costMeasure navigation timing

#Checklist

  • Every preload specifies as, and fonts include crossorigin
  • Preloading is limited to render-blocking resources
  • preconnect is used only for origins certain to be needed
  • Future navigations use prefetch, not preload
  • Prefetching is triggered by hover, focus or a known flow step
  • Speculation rules start at conservative eagerness
  • No page with load-time side effects is prerendered
  • Prerendered pages gate analytics on visibility
  • At most one or two destinations are prerendered
  • Save-Data and slow connections disable prefetching
  • Prefetch targets are cacheable, not no-store
  • Authenticated and personalised URLs are never speculatively fetched
  • The effect of prefetching on navigation timing is measured