Which project does this relate to?
Start
Describe the bug
My goal with my app is to use TanStack Start hosted on Cloudflare with normal app routes served as static client-rendered pages, while API routes and server functions are still handled by Workers.
Cloudflare Static Assets SPA mode expects a real SPA fallback file, usually /index.html. Since TanStack Start SPA mode generates /_shell.html, I wanted to verify that the shell is route-neutral before copying/remapping it to /index.html.
From the SPA mode docs, my understanding is that spa.enabled: true should prerender only the root shell and should not include matched route content or route loader data. The Selective SSR docs also seem to say SPA mode disables server-side route loader execution and route-component SSR.
However, when using the official Cloudflare setup with @cloudflare/vite-plugin, the generated dist/client/_shell.html includes the / route component HTML and loader data.
This is already visible in the build output, so to me it does not appear to be a Cloudflare runtime/routing issue.
Complete minimal reproducer
Created using the start-basic-cloudflare example, removing the unused routes and enabling spa mode.
https://github.com/bbertold/tanstack-start-shell-issue
Steps to Reproduce the Bug
- Clone the reproducer
- Install dependencies with
npm install
- Run the build command
- Open
dist/client/_shell.html
The generated shell contains the / route content:
<div class="p-2">
<h3>Welcome Home!!!</h3>
<p>Running in Cloudflare-Workers</p>
<p>Hello from Cloudflare</p>
</div>
It also serializes the / route match and loader data:
routes: {
__root__: ...,
"/": ...
},
matches: [
{ i: "__root__\0", s: "success", ssr: true },
{
i: "\0\0",
s: "success",
l: {
message: "Running in Cloudflare-Workers",
myVar: "Hello from Cloudflare"
},
ssr: true
}
]
The relevant SPA config is:
tanstackStart({
spa: {
enabled: true,
},
})
I also tried changing plugin order, but both produced the same shell output.
Expected behavior
I expected dist/client/_shell.html in SPA mode to contain only the root shell/layout, without rendering the matched / route component and without serializing / route loader data.
Root layout/nav output from shellComponent seems expected. The unexpected part is the index route content being rendered inside {children}.
For Cloudflare Static Assets SPA hosting, I expected this shell to be safe to use as a route-neutral fallback file, such as /index.html.
Screenshots or Videos
No response
Platform
The core package versions are same as in the start-basic-cloudflare example.
- Router / Start Version: 1.170.17
- OS: macOS
- Browser: Chrome
- Browser Version: 150.0.7871.46
- Bundler: vite
- Bundler Version: 8.0.14
Additional context
I also tested a similar TanStack Start app without the Cloudflare Vite plugin, using the Nitro setup. In that case, there were no issues, only the root match was serialized, with no / route content or loader data. That makes me think this may be specific to the Cloudflare Vite plugin integration.
Which project does this relate to?
Start
Describe the bug
My goal with my app is to use TanStack Start hosted on Cloudflare with normal app routes served as static client-rendered pages, while API routes and server functions are still handled by Workers.
Cloudflare Static Assets SPA mode expects a real SPA fallback file, usually /index.html. Since TanStack Start SPA mode generates
/_shell.html, I wanted to verify that the shell is route-neutral before copying/remapping it to/index.html.From the SPA mode docs, my understanding is that
spa.enabled: trueshould prerender only the root shell and should not include matched route content or route loader data. The Selective SSR docs also seem to say SPA mode disables server-side route loader execution and route-component SSR.However, when using the official Cloudflare setup with
@cloudflare/vite-plugin, the generateddist/client/_shell.htmlincludes the/route component HTML and loader data.This is already visible in the build output, so to me it does not appear to be a Cloudflare runtime/routing issue.
Complete minimal reproducer
Created using the
start-basic-cloudflareexample, removing the unused routes and enablingspamode.https://github.com/bbertold/tanstack-start-shell-issue
Steps to Reproduce the Bug
npm installdist/client/_shell.htmlThe generated shell contains the / route content:
It also serializes the / route match and loader data:
The relevant SPA config is:
I also tried changing plugin order, but both produced the same shell output.
Expected behavior
I expected
dist/client/_shell.htmlin SPA mode to contain only the root shell/layout, without rendering the matched / route component and without serializing / route loader data.Root layout/nav output from shellComponent seems expected. The unexpected part is the index route content being rendered inside
{children}.For Cloudflare Static Assets SPA hosting, I expected this shell to be safe to use as a route-neutral fallback file, such as /index.html.
Screenshots or Videos
No response
Platform
The core package versions are same as in the
start-basic-cloudflareexample.Additional context
I also tested a similar TanStack Start app without the Cloudflare Vite plugin, using the Nitro setup. In that case, there were no issues, only the root match was serialized, with no / route content or loader data. That makes me think this may be specific to the Cloudflare Vite plugin integration.