Prefetching Links in Astro
Astro ships its own link prefetching: a small script that watches links on the page and fetches their target pages before the reader clicks, so navigations start from the HTTP cache rather than the network. It is off by default for most sites, takes one line to enable, and has four strategies whose trade-offs are worth understanding before turning it on everywhere. With the experimental clientPrerender flag, the same configuration emits Speculation Rules in supporting browsers, upgrading prefetch to full prerender.
This guide configures prefetch for an Astro marketing and docs site, chooses a strategy per link type, and measures the effect on navigation. It is part of Resource Hints and Navigation Speed; the browser-level API behind clientPrerender is covered in Instant Navigation with Speculation Rules.
Prerequisites
- Astro 4.2 or newer (prefetch became built-in in 3.5;
clientPrerenderarrived in 4.2). - A static build (
output: 'static'). - Some idea of which links readers follow most — analytics exit pages or a simple click log.
Step 1: Turn It On
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
prefetch: {
prefetchAll: false, // opt links in explicitly
defaultStrategy: 'hover',
},
experimental: {
clientPrerender: true, // speculation rules where supported
},
});
With prefetchAll: false, only links carrying data-astro-prefetch are prefetched. That is the safer starting point: it forces a decision per link type instead of prefetching every footer and legal link. With prefetchAll: true, every same-origin link is a candidate and data-astro-prefetch="false" opts individual links out.
If the site uses Astro's <ClientRouter /> for view transitions, prefetching is enabled automatically with prefetchAll: true and the hover strategy — worth knowing, because teams sometimes discover the extra requests only in CDN logs.
Step 2: Choose a Strategy per Link Type
Astro offers four strategies, set per link with the attribute value:
| Strategy | Fires when | Good for | Cost |
|---|---|---|---|
hover | pointer hovers or keyboard focus | general navigation, sidebar, in-content links | low |
tap | just before click (touchstart/mousedown) | large link lists, bandwidth-sensitive pages | lowest |
viewport | link scrolls into view | pagination, "next article", short card grids | medium |
load | page load, after idle | the one link nearly everyone follows | highest |
<!-- Docs sidebar: hover -->
<a href={item.href} data-astro-prefetch>{item.label}</a>
<!-- "Next page" link at the bottom of each guide: viewport -->
<a href={next.href} data-astro-prefetch="viewport">Next: {next.title} →</a>
<!-- Homepage primary call to action: load -->
<a href="/docs/getting-started/" data-astro-prefetch="load">Get started</a>
<!-- Footer and legal links: none -->
<a href="/legal/privacy/">Privacy</a>
Step 3: Prefetch Programmatically Where Needed
Some navigations are predictable but not links — a search result list that appears after typing, or a "continue" button driven by JavaScript. Astro exposes the same mechanism as a function:
<script>
import { prefetch } from 'astro:prefetch';
document.addEventListener('search:results', (e) => {
const first = e.detail.results[0]?.url;
if (first) prefetch(first, { eagerness: 'moderate' });
});
</script>
Prefetching the first search result when results render made the "search, then click the top result" journey noticeably faster: the result page was usually cached by the time the reader clicked, 300–800 ms after results appeared. The search setup itself is in Adding Pagefind to an Astro Site.
Step 4: Verify in DevTools
In the Network panel, prefetched documents appear with type document and priority Lowest, and the later navigation shows (prefetch cache) or, with clientPrerender, nothing at all because the page was already rendered. With clientPrerender enabled, Chrome's Application → Speculative loads panel lists the generated rules and each candidate's status. Test both with and without the experimental flag in a browser that lacks speculation rules support, to confirm the fallback path works.
Measured Impact
The Astro site (220 pages: marketing, docs, blog) was measured in three configurations for two weeks each, field data from web-vitals beacons, internal navigations only.
| Configuration | Click-to-LCP p50 (all browsers) | p50 (Chrome) | Prefetch requests per page view | Unused prefetch rate |
|---|---|---|---|---|
| No prefetch | 580 ms | 560 ms | 0 | — |
prefetch, strategies per link type | 270 ms | 250 ms | 1.4 | 41% |
+ clientPrerender | 170 ms | 60 ms | 1.4 | 41% |
prefetchAll + viewport everywhere (for comparison) | 250 ms | 240 ms | 9.8 | 92% |
The last row is the cautionary one: prefetching every link on scroll-into-view spent 9.8 requests per page view, 92% of them never used, for a result no better than targeted strategies. On a page with a long card grid, viewport prefetch fetched 30 pages as the reader scrolled.
How Prefetch Interacts With the Rest of the Stack
Three interactions are worth checking once prefetch is live. Caching headers: a prefetched page is only reused if the HTTP cache still considers it fresh when the reader clicks; with Cache-Control: max-age=0, must-revalidate on HTML, Chrome revalidates on navigation and part of the gain disappears. A short max-age of 60–300 seconds on HTML keeps prefetches reusable without delaying deploys noticeably, as covered in Stale-While-Revalidate for Static HTML. Analytics: plain prefetch downloads HTML without executing it, so it never inflates page views; clientPrerender does execute scripts, so the prerender-aware analytics gate from the speculation rules guide is required. Islands: with prerender, hydration of client:load islands happens before the reader arrives, so interactive components are ready immediately — a quiet INP improvement for pages whose first interaction happens right after navigation.
Mobile and Metered Connections
Astro's prefetch script already skips prefetching when the browser reports Data Saver (navigator.connection.saveData) or a 2g connection, which covers the most obvious cases. Two further decisions are yours. First, hover does not exist on touch devices, so the hover strategy falls back to focus and effectively does nothing for most mobile taps; for mobile-heavy sites, tap on general links gives a small head start (the gap between touchstart and click is typically 80–150 ms) without speculative waste. Second, reserve viewport and load for links with a high click probability — on this site, the "next page" link at the end of docs guides was followed in 34% of mobile sessions, which justified viewport, while a card grid of related posts had a 3% click rate per card and did not.
Measure the balance with two numbers from RUM and CDN logs: the share of navigations that were served from prefetch, and the share of prefetches that were never used. A healthy configuration serves more than half of internal navigations from prefetch while keeping unused prefetches below about half; the targeted setup here reached 58% and 41%.
Pitfalls & Rollback
prefetchAllwithviewport. Every visible link fetched on scroll wastes bandwidth on card-heavy pages. Keepviewportfor small, likely link sets.- Forgetting ClientRouter's default. Adding view transitions silently turns on prefetch for all links. Check the config and decide deliberately.
- Prerender without prerender-aware analytics.
clientPrerenderruns page scripts before activation; gate page views onprerenderingchange. - Prefetching downloads. Exclude links to PDFs and archives with
data-astro-prefetch="false". - Rollback: set
prefetch: falsein the config to disable everything, or removeclientPrerenderto drop back to plain prefetch. Link attributes can stay; they are ignored when prefetch is off.
Conclusion
Astro's prefetch is a one-line feature with a strategy decision behind it. Opt links in by type — hover for navigation, viewport for the "next" link, load for the one call to action nearly everyone clicks, nothing for footers — and enable clientPrerender to upgrade to full prerendering in supporting browsers. On a 220-page site that cut median click-to-LCP from 580 ms to 170 ms across all browsers and to 60 ms in Chrome, at 1.4 extra requests per page view, while prefetching every visible link spent seven times the requests for no additional gain.
FAQ
Is prefetching enabled by default in Astro?
Only when you use view transitions via the ClientRouter component, which turns prefetching on for all links with the hover strategy. Otherwise, set prefetch to true in astro.config and opt links in with the data-astro-prefetch attribute, or set prefetchAll.
Which prefetch strategy should I use?
Hover for most links, viewport for small, high-probability link sets such as a pagination bar, tap for links on mobile-heavy pages where bandwidth matters, and load only for one or two links you are confident the reader will follow.
What does experimental clientPrerender do?
It makes Astro emit Speculation Rules instead of prefetch links in browsers that support them, so hovered pages are fully prerendered rather than just downloaded. Browsers without support fall back to the normal prefetch behaviour.
Does prefetching add JavaScript to every page?
Yes, a small script of about 1.5 KB compressed that watches links and inserts prefetch requests. It loads with low priority and does not block rendering.
Related
- Parent: Resource Hints and Navigation Speed — all navigation hints compared.
- Instant Navigation with Speculation Rules — the browser API behind clientPrerender.
- View Transitions on Multi-Page Static Sites — pairing prefetch with animated navigation.
- Optimizing LCP on Astro with Priority Hints — the first-load side of Astro performance.
- Astro Islands vs Full Hydration Performance — why prerendered islands help INP.