T
TanStack2mo ago
afraid-scarlet

Cloudflare Prerendering

I noticed there aren't any specific instructions on Cloudflare prerendering. When I followed the Cloudflare guide and then enabled prerendering, I got build errors about compatibilityFlags. I was able to remove the cloudflare() plugin and then use this wrangler.jsonc:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "tanstack-start-hybrid",
"compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat"],
"main": "./dist/server/server.js",
"assets": {
"directory": "./dist/client"
},
"observability": {
"logs": {
"enabled": true,
"head_sampling_rate": 1,
"invocation_logs": true
}
}
}
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "tanstack-start-hybrid",
"compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat"],
"main": "./dist/server/server.js",
"assets": {
"directory": "./dist/client"
},
"observability": {
"logs": {
"enabled": true,
"head_sampling_rate": 1,
"invocation_logs": true
}
}
}
With prerender: { enabled: true } this seems to work now. Are there any downsides with this setup, since I've removed the cloudflare plugin from my vite.config.ts?
import tailwindcss from "@tailwindcss/vite"
import { tanstackStart } from "@tanstack/react-start/plugin/vite"
import viteReact from "@vitejs/plugin-react"
import { defineConfig } from "vite"
import devtoolsJson from "vite-plugin-devtools-json"
import viteTsConfigPaths from "vite-tsconfig-paths"

const config = defineConfig({
plugins: [
viteTsConfigPaths({
projects: ["./tsconfig.json"]
}),
tailwindcss(),
tanstackStart({
prerender: {
enabled: true
},
}),
viteReact(),
devtoolsJson()
]
})

export default config
import tailwindcss from "@tailwindcss/vite"
import { tanstackStart } from "@tanstack/react-start/plugin/vite"
import viteReact from "@vitejs/plugin-react"
import { defineConfig } from "vite"
import devtoolsJson from "vite-plugin-devtools-json"
import viteTsConfigPaths from "vite-tsconfig-paths"

const config = defineConfig({
plugins: [
viteTsConfigPaths({
projects: ["./tsconfig.json"]
}),
tailwindcss(),
tanstackStart({
prerender: {
enabled: true
},
}),
viteReact(),
devtoolsJson()
]
})

export default config
23 Replies
afraid-scarlet
afraid-scarletOP2mo ago
What exactly does the cloudflareplugin do? And is it fine to just have the main entry point set to dist/server/server.ts This is the build error when I use cloudflare({ viteEnvironment: { name: "ssr" }}) plugin along with prerender: { enabled: true }
[prerender] Prerendering pages...
error during build:
TypeError: Cannot read properties of undefined (reading 'compatibilityFlags')
at file:///Users/david/Developer/tanstack-start-hybrid/dist/server/assets/worker-entry-ZLDVsmU5.js:333:50
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async prerender (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/prerender.js:50:41)
at async postServerBuild (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/post-server-build.js:39:5)
at async Object.buildApp (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/plugin.js:245:15)
at async Object.buildApp (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/vite@7.1.11_@types+node@24.9.1_jiti@2.6.1_lightningcss@1.30.2_tsx@4.20.6/node_modules/vite/dist/node/chunks/config.js:34139:38)
at async CAC.<anonymous> (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/vite@7.1.11_@types+node@24.9.1_jiti@2.6.1_lightningcss@1.30.2_tsx@4.20.6/node_modules/vite/dist/node/cli.js:629:3)
[prerender] Prerendering pages...
error during build:
TypeError: Cannot read properties of undefined (reading 'compatibilityFlags')
at file:///Users/david/Developer/tanstack-start-hybrid/dist/server/assets/worker-entry-ZLDVsmU5.js:333:50
at ModuleJob.run (node:internal/modules/esm/module_job:274:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async prerender (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/prerender.js:50:41)
at async postServerBuild (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/post-server-build.js:39:5)
at async Object.buildApp (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/@tanstack+start-plugin-core@1.133.22_@tanstack+react-router@1.133.22_react-dom@19.2.0_r_de33004ae12819f8b7e5deae13fe8864/node_modules/@tanstack/start-plugin-core/dist/esm/plugin.js:245:15)
at async Object.buildApp (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/vite@7.1.11_@types+node@24.9.1_jiti@2.6.1_lightningcss@1.30.2_tsx@4.20.6/node_modules/vite/dist/node/chunks/config.js:34139:38)
at async CAC.<anonymous> (file:///Users/david/Developer/tanstack-start-hybrid/node_modules/.pnpm/vite@7.1.11_@types+node@24.9.1_jiti@2.6.1_lightningcss@1.30.2_tsx@4.20.6/node_modules/vite/dist/node/cli.js:629:3)
quickest-silver
quickest-silver2mo ago
the cloudflare plugin configures the build so that the output runs on workerd it also ties into wrangler prerendering with the cloudflare plugin is being worked on
afraid-scarlet
afraid-scarletOP2mo ago
ok cool. Somehow everything is still working for me when I manually set the wrangler to use the dist/server/server.ts and remove the cloudflare plugin. So I wasn't sure like what specifically could be broken with that setup I guess I'll just use it like that for now until something noticeable breaks and then update my setup whenever the official support for prerendering with the cloudflare plugin is ready
like-gold
like-gold2mo ago
w/o the plugin you probably wouldn't be able to use bindings locally i believe since it does handle platform proxies
afraid-scarlet
afraid-scarletOP2mo ago
I see so potentially environment variables might not work Unless they are still accessible via process.env
afraid-scarlet
afraid-scarletOP2mo ago
https://github.com/cloudflare/workers-sdk/blob/7f7ec7fea2e2dd97b51e7aa417c0b03c798a159e/packages/unenv-preset/src/runtime/node/process.ts#L26 This is the line where the crash is, I think could be fixed with optional chaining pretty easily? But idk if there's any other issues
GitHub
workers-sdk/packages/unenv-preset/src/runtime/node/process.ts at 7f...
⛅️ Home to Wrangler, the CLI for Cloudflare Workers® - cloudflare/workers-sdk
afraid-scarlet
afraid-scarletOP2mo ago
Yea I put this line at the top of my vite.config.ts and it fixes pre-rendering: ;(globalThis as any).Cloudflare = { compatibilityFlags: {} } Ah it doesn't actually proceed with the prerender though whoops, skips the files but doesn't crash
quickest-silver
quickest-silver2mo ago
we are working on supporting prerendering with cloudflare right now prerendering does not run using wrangler and hence fails when you reference cloudflare env during prerendering
afraid-scarlet
afraid-scarletOP2mo ago
While on the topic of pre-rendering, I have a slight issue. I want to make my home page / static, however I want to have a cookie redirect on this home page. Is that not possible using TSS? I think with Next.js it worked with middleware because it ran before serving the static asset I also noticed pre-rendering crashes on any page that returns a redirect from custom server.ts To fix the crashing during pre-rendering I set this up:
import handler from "@tanstack/react-start/server-entry"

export default {
fetch(request: Request) {
if (process.env.TSS_PRERENDERING !== "true") {
const url = new URL(request.url)
if (url.pathname === "/test") {
return Response.redirect(`${url.origin}/`, 302)
}
}

return handler.fetch(request)
}
}
import handler from "@tanstack/react-start/server-entry"

export default {
fetch(request: Request) {
if (process.env.TSS_PRERENDERING !== "true") {
const url = new URL(request.url)
if (url.pathname === "/test") {
return Response.redirect(`${url.origin}/`, 302)
}
}

return handler.fetch(request)
}
}
I guess the issue is that when a static prerendered page gets requested, it skips custom server entirely ? I'm trying to create a middleware for automatically redirecting based on LOCALE cookie when visiting the root route. Maybe this should simply be in beforeLoad, that way I can perform the redirect client side for static pre-rendered pages, and server side for SSR pages
quickest-silver
quickest-silver2mo ago
just merged a PR that should fix the redirect
afraid-scarlet
afraid-scarletOP2mo ago
Lol literally typing GH issue up rn I'll check it out Okay I have an interesting thing happening now. For a prerendered route that got redirected, in this example, /test always redirects to /, it initially renders / from static prerender, then the client immediately flickers it back to /test client side render
afraid-scarlet
afraid-scarletOP2mo ago
No description
afraid-scarlet
afraid-scarletOP2mo ago
[prerender] Prerendered 4 pages:
[prerender] - /
[prerender] - /test
[prerender] - /posts/94
[prerender] - /posts/4
[prerender] Prerendered 4 pages:
[prerender] - /
[prerender] - /test
[prerender] - /posts/94
[prerender] - /posts/4
import handler from "@tanstack/react-start/server-entry"

export default {
fetch(request: Request) {
const url = new URL(request.url)
if (url.pathname === "/test") {
return Response.redirect(`${url.origin}/`, 302)
}

return handler.fetch(request)
}
}
import handler from "@tanstack/react-start/server-entry"

export default {
fetch(request: Request) {
const url = new URL(request.url)
if (url.pathname === "/test") {
return Response.redirect(`${url.origin}/`, 302)
}

return handler.fetch(request)
}
}
quickest-silver
quickest-silver2mo ago
redirecting on the request level will give you that when the client hydrates on /test, how would it know about that server redirect that happend at prerendering time
afraid-scarlet
afraid-scarletOP2mo ago
Right so it needs some sort of client middleware to do a redirect for a static page Doesn't seem like it's possible to do a server-side redirect before rendering the static page, in Next.js it was handled via Middleware (now Proxy) which runs as a pre-request pretty much But rewrites will work for static pages ? It would be cool if there was some way to do a redirect before rendering the static page, so static "/test" is never accessible Yea it looks like rewrites also do not work for prerendered pages
rewrite: {
input: ({ url }) => {
if (url.pathname === "/test") {
url.pathname = "/"
}

return url
}
}
rewrite: {
input: ({ url }) => {
if (url.pathname === "/test") {
url.pathname = "/"
}

return url
}
}
This has the same outcome, I commented out the server.ts. This again flickers / SSR into /test https://developers.cloudflare.com/workers/static-assets/redirects/ This is interesting It would be super cool if the prerender could detect a redirect and then append it to _redirects in the static assets Then it doesn't even have to render /test in that case right Prerenderer fetches /test -> Checks response for a redirect, if there's a redirect, appends it to _redirects and skips the prerender Putting a _redirects file in my public folder with /test / 302 correctly does the redirect
quickest-silver
quickest-silver2mo ago
that's a platform specific thing though
afraid-scarlet
afraid-scarletOP2mo ago
Yea maybe a part of the cloudflare plugin or something, idk
quickest-silver
quickest-silver2mo ago
we could ofcourse give you a callback function option where you are notified of a redirect and then implement platform specific stuff
afraid-scarlet
afraid-scarletOP2mo ago
This seems like paraglidejs might break with prerendered pages since it uses rewrites Haven't tested it yet though
quickest-silver
quickest-silver2mo ago
lets ask @Júlio Mühlbauer about this since he uses paraglide
afraid-scarlet
afraid-scarletOP2mo ago
Maybe rewrites should be applied to the client as well? So like if you have a rewrite of /test to /, and the SPA navigates to prerendered /test, it should render / instead of /test Another interesting discovery.. There is this "run_worker_first" option in wrangler that invokes the worker before serving a static request. Maybe some how this can be configured to invoke global middleware only. Effectively becoming "edge middleware" to static assets - https://developers.cloudflare.com/workers/static-assets/routing/worker-script/#run-worker-first-for-selective-paths Ah! Looks like I might be wrong about rewrites. It was adding a trailing slash to /test/ I had to set "html_handling": "drop-trailing-slash" in my wrangler, looks like rewrites are working on client now. Which means paraglide rewrites should work just fine on prerendered pages
rival-black
rival-black5w ago
Interestingly also received similar bug reports on my side, is there an issue that we can track the progress? or having it documented would be great, currently it is hard to know the unsupported features until it's confirmed on Discord or in a GitHub issue thread
quickest-silver
quickest-silver5w ago
nothing public yet. feel free to create a PR for our docs to mention this being WIP

Did you find this page helpful?