cloudflare

speed brain

edge-side prefetch via speculation rules — conflicts with framework prefetching

speed brain

cloudflare's edge-side prefetch. injects a Speculation-Rules header into html responses so browsers prefetch the next likely navigation before the user clicks.

what it does

cloudflare adds a speculation rules config to every html response:

{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*","relative_to":"document"}]},"eagerness":"moderate"}]}

the browser reads this and prefetches same-origin links. prefetch requests carry a Sec-Purpose: prefetch header.

prefetch only serves from cloudflare's cache. if the page isn't cached, cloudflare returns a 503 with an empty body. requests never reach origin.

eagerness levels

level trigger
conservative mousedown / touchstart
moderate hover
eager viewport

cloudflare defaults to moderate.

conflict with framework prefetching

astro, next.js, nuxt — all have their own prefetch systems. they send requests with the same Sec-Purpose: prefetch header that speed brain watches for.

both active at once: cloudflare intercepts the framework's prefetch at the edge, page isn't in cache, 503. browser logs failed resource loads. actual navigation works fine — only prefetch breaks.

use one or the other. for static sites where every page is already on the cdn, framework prefetching is simpler — no cache-eligibility gate, no 503s.

issue i had

astro configured with prefetchAll: true and defaultStrategy: 'viewport'. speed brain also enabled. every prefetch request returned 503:

cf-speculation-refused: prefetch refused: not eligible
vary: sec-purpose
content-length: 0

disabled speed brain, 503s stopped.