The one idea
TanStack Start is full-stack React on the type-safe TanStack Router: file-based routes + server functions (typed RPC) + SSR. The pick when your site is an APP, not content. v1 RC · not yet GA
Astro owns the ~80% of the web where content is king (zero JS by default). TanStack Start owns the app-like SaaS lane: the whole page is the product, rich client interactivity is the point, and you want type-safety to flow from the URL all the way into the server boundary. One question decides it: is the page mostly read, or mostly interacted with?
The stack — three layers
Start is built ON TanStack Router — the routing layer is the foundation. Server Functions are the typed RPC boundary. Nitro handles SSR and the deployable server output. Vite is the bundler underneath all of it.
React Server Components support is on the way as a non-breaking v1.x addition — not assumed today. Cross-ref: 🔗 metaframework_landscape (the comparison map).
Server-function flow — type-safety flows end to end
A server function is typed RPC, not a REST endpoint. You call it like a normal async function on the client; the framework wires the network boundary. The validator types the input; the handler's return types the result — both flow back to the caller. Click run to trace it.
// typed call crosses the wire
const user = await getUser({
data: 42
});
// validator: input typed + validated .validator((id: number) => id) // handler runs ONLY on the server .handler(async ({ data }) => { … })
// server-only: real data access
return await db.user
.findUnique({ where: {
id: data } });
// result is typed end-to-end user.id // number user.name // string
Decision helper — content site or SaaS app?
Deterministic: the same answers always return the same pick. Try the app-like + full-server
+ type-safe-obsessed path → it returns TanStack Start (asserted by the gold-check).
Where Start sits vs Astro
(content-first, zero-JS)
(app, full-React, typed server)