@roostjs/start

Why Roost integrates with TanStack Start, how the context bridge connects server and client, and what SSR looks like on Workers.

Why TanStack Start Over Next.js or Remix

The React full-stack framework space has several contenders. Next.js is the most widely deployed. Remix prioritizes web fundamentals. Both are designed primarily for Node.js and have varying levels of support for edge runtimes. TanStack Start is different in a relevant way: it is runtime-agnostic at its core and designed to run on Cloudflare Workers as a first-class deployment target, not as an afterthought.

More concretely, TanStack Start's routing model is file-based but builds on TanStack Router, which has some of the strongest TypeScript integration of any React router. Route params are typed. Loader data is typed. Search params are validated and typed. For applications that take TypeScript seriously, this type safety propagates from the URL into the component tree without manual casting. That alignment with Roost's TypeScript-first design made TanStack Start the right foundation.

The Context Bridge

Roost runs server-side: it boots, registers providers, and makes services available through the container. TanStack Start runs server-side rendering and client-side hydration. The challenge is connecting these two systems so that server functions and route loaders can access Roost's container — the authenticated user, resolved organization, database connection — without the container being globally mutable state.

The @roostjs/start package solves this with a context bridge. The Roost Application is bootstrapped once and cached. For each request, a scoped container is created and attached to TanStack Start's server context. Server functions defined with roostFn capture this context and can resolve services from it. The bridge is the mechanism that makes the scoped container travel through TanStack Start's data-loading layer without being a global singleton.

SSR on Workers vs. Node.js

Server-side rendering in Node.js typically means a long-running process that handles React's renderToString or streaming equivalents. On Workers, there is no persistent server process — each request is handled fresh (possibly by a warm isolate, but without server-process-level assumptions). This means SSR happens per-request, which is actually the semantically correct behavior for dynamic applications: every visitor gets a server render reflecting the current server state, not a stale render from a warm cache.

The Workers runtime includes V8's streaming APIs, so TanStack Start's streaming SSR works natively. The main practical difference from Node.js is that Workers do not have Node.js built-ins, so any SSR code or its dependencies must be compatible with the Web Platform APIs. TanStack Start is designed for this; Roost's integration does not paper over any incompatibilities.

Further Reading