Skip to main content
← Back to writing

The Speculation Rules API: Instant Navigations, Real Trade-offs

TL;DR: The Speculation Rules API lets a page tell the browser which links to prefetch or prerender in advance, so the next navigation lands instantly. It’s a clean declarative JSON API with a tunable “eagerness” dial — and it works beautifully when you can predict the next click. The catch is that prerendering spends real bandwidth, CPU, and server load on pages the user may never open, and it’s Chromium-only. A precision tool, not a default. Verdict: 🟣 hold for now.

🎯 Why It Was Worth Evaluating

“Make the next page feel instant” is one of the highest-leverage moves in all of perceived performance, and this API promises it for almost no code. So the evaluation was never about whether it works — it does. It was about the bill: what does the speed actually cost, and can you spend it responsibly on client sites with real traffic and real devices?

🔍 How It Works

You drop a <script type="speculationrules"> block (or send the equivalent HTTP header) describing what to speculate on:

<script type="speculationrules">
{
  "prerender": [
    {
      "where": { "href_matches": "/products/*" },
      "eagerness": "moderate"
    }
  ],
  "prefetch": [
    {
      "where": { "selector_matches": "a.nav-link" },
      "eagerness": "conservative"
    }
  ]
}
</script>

Two speculation types with wildly different cost profiles:

  • Prefetch fetches the document response ahead of time — cheap, it’s just HTML.
  • Prerender fully renders the next page in a hidden tab, JavaScript and all. On click, it’s swapped in instantly — expensive, because it’s an entire page load you might throw away.
flowchart LR
    A["User on page A"] --> B{"Speculation<br/>rule matches?"}
    B -->|prefetch| C["Fetch document<br/>(HTML only)"]
    B -->|prerender| D["Render page B<br/>in hidden tab"]
    C --> E["User clicks link"]
    D --> E
    E --> F["Near-instant<br/>navigation to B"]

Eagerness is the whole game

The eagerness dial decides how aggressively the browser gambles resources on your guess. Tune it wrong and you’ve built a bandwidth furnace:

EagernessTriggers when…Best for
immediateThe rule is parsedA high-confidence single next step
eagerSlightly less aggressiveLikely-but-not-certain paths
moderateOn hover (~200ms)A sensible default for link lists
conservativeOn pointer/touch downMinimizing wasted speculation

⚖️ Where the “Hold” Comes From

The benefits are real; so is the bill, and the bill is what tipped the verdict:

  • Wasted compute. Prerendering runs the target page’s JavaScript. On a budget phone, that’s a genuine battery and CPU tax for a navigation that may never happen.
  • Server load. Every speculative render is a real request to your origin. Aggressive rules multiply traffic — exactly the wrong behavior on a high-traffic site.
  • Compatibility. It’s Chromium-only. Firefox and Safari users get nothing, so it can only ever be a progressive enhancement, never a guarantee.
  • Side effects. Prerendered pages fire analytics and run effects. You have to make sure a speculated-but-unvisited page doesn’t log a phantom pageview or mutate state — a subtle correctness trap.

🧭 Where It Genuinely Earns Its Keep

This is a “keep it in your back pocket for the right client” capability, not a site-wide default. It shines when there’s a high-probability next navigation — list → detail, a paginated flow, a funnel with an obvious next step — and a Chromium-skewed audience. Point it at a general content site with unpredictable browsing and the wasted-work ratio quietly eats the win.

Verdict

🟣 Hold for now. The right outcome here was awareness over adoption: make sure the team knows this exists and reaches for it deliberately on the project that fits. It’s a scalpel — devastatingly effective when the next click is predictable, and a waste of resources when it isn’t.