Cloudflare moves Next.js prerendering off the build machine
Summary
Vinext's cache warming moves page rendering off the build machine and onto Cloudflare's network. That removes a real build-time bottleneck, and it hands part of the coverage decision to a traffic heuristic Cloudflare's post does not describe.
Anyone evaluating the migration should enumerate the URLs that need to be fast using the Next.js primitives, then sample the long tail after a deploy to find out what the warming pass actually reached.
Cloudflare shipped Vinext 1.0 this week, seven months after releasing it as an experiment in running Next.js on Vite, a build tool. Vinext takes a Next.js app built for either the App or Pages Router and makes it deployable elsewhere, including Cloudflare Workers, Netlify and AWS Lambda. Version 1.0 adds prerendering during the build for both routers, page-level ISR layered on those responses, revalidation by path or tag, and output: "export" for a fully static site. It also offers a way to skip the build render entirely.
Cache warming is that alternative. Instead of rendering pages on the build machine, the deployment process uploads the new Worker version, deploys it to 0% of production traffic, then requests pages from that version specifically so the responses land in Cloudflare’s cache. Once the cache holds them, the version is promoted and real traffic arrives to warm responses. Cloudflare’s case for it is build duration: a site with hundreds of thousands of possible URLs spends hours rendering pages that receive little traffic, and the build has no way to separate the important routes from the long tail.
The argument holds. What it changes is where the decision about your URLs gets made.
Two inputs feed the warming list, and only one of them is yours. Developers keep using the Next.js primitives, generateStaticParams() and getStaticPaths(), to name the pages they want rendered ahead of time. Vinext then adds pages it identifies as high-traffic. Cloudflare’s post does not say how that second list is built, how many URLs it holds, or what window of traffic it reads, and it does not say whether crawler requests count as traffic for the purpose. On a catalogue far larger than any warming pass would cover, that unspecified half decides which pages are fast.
Everything off the list is served cold, and the first requester pays the render. On a large catalogue the likelier first requester is Googlebot rather than a person, because the pages outside the warming list are by definition the ones nobody visits. A single server render on a Worker is not slow in absolute terms, but it is a render, and it sits inside TTFB for whoever triggers it. Cloudflare’s post does not measure any crawl effect, so treat that as a thing to check on your own logs rather than a known cost.
None of this is an argument against the migration. The build-time path still exists in 1.0, so a site that can enumerate its important URLs can keep doing exactly what it does now and take the warming pass as a bonus on top. The harder constraint is compatibility: Cloudflare puts test compatibility above 99% for the features customers asked for, but explicitly excludes cache components, and support for the "use cache" directive that drives them is limited. An app that has already adopted Cache Components is not a candidate yet.
What to do
- Run
npx vinext checkon a branch before forming any view on the rest. It reports whether your install and your modifications are compatible, which settles the question faster than reading release notes. - List every URL that needs to be fast in
generateStaticParams()orgetStaticPaths(), rather than relying on Vinext’s traffic detection to find them. That list is the only half of the warming pass you control. Decide it per template, not site-wide: in one Sitebulb case, moving category listings into HTML lifted top-3 keywords 28% while checkout pages stayed client-rendered. - After a deploy, request a sample of long-tail URLs and compare TTFB on the first hit against the second. A gap means that URL was outside the pass, and the size of the sample that shows a gap tells you the real coverage.
- Check server logs for which templates Googlebot hits most in a crawl cycle, then make sure those paths are in the explicit list. Bot traffic and user traffic diverge most on exactly the pages the warming heuristic is least likely to pick.
- If the app depends on Cache Components, stay on Next.js and revisit later. Teams still choosing a framework rather than porting one face a different question, covered in the Astro vs Next.js comparison for SEOs.