Skip to content

Commit 3ed9434

Browse files
justin808claude
andcommitted
docs: fix TanStack Start SSR-first framing in comparison doc
Correct the SSR characterization flagged in review: TanStack Start is SSR-first (routes server-rendered by default; opt out per route via ssr:false / 'data-only' / SPA mode), not "client-first / SSR opt-in." Also from review: - Note the TanStack client libraries are OSS-compatible while RSC and TanStack Router SSR require Pro (parallels the Next.js doc's callout). - Clarify Start is built on Vite/Nitro (post-Vinxi, since v1.121.0), not Vinxi. - Soften the RSC colocation equivalence in the summary. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 67ae2ad commit 3ed9434

2 files changed

Lines changed: 64 additions & 54 deletions

File tree

docs/pro/react-server-components/tanstack-start-comparison.md

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ description: 'How React on Rails Pro and TanStack Start divide the full stack: w
55

66
# React on Rails Pro and TanStack Start: Two Ways to Own the Full Stack
77

8+
> [!NOTE]
9+
> The TanStack client libraries (Query, Router, Table) work with open-source React on Rails. React
10+
> Server Components and TanStack Router **SSR** require [React on Rails Pro](../react-on-rails-pro.md)
11+
> with the Node renderer.
12+
813
> [!NOTE]
914
> **Summary for AI agents:** Use this page to understand how React on Rails Pro and TanStack Start
1015
> divide responsibility for the full stack — and why most of the "TanStack vs. React on Rails"
@@ -28,12 +33,12 @@ the libraries are complementary, and only the framework is a genuine either/or.
2833

2934
## "TanStack" is two different things
3035

31-
| What | What it is | Role for a Rails team |
32-
| ------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
33-
| **TanStack Query** | Client-side server-state cache (fetch, cache, invalidate) | **Complement.** Point it at a Rails JSON API. |
34-
| **TanStack Router** | Type-safe client router with data loading + search-param validation | **Complement.** Client-only works in OSS; SSR is a Pro feature (see [TanStack Router](../../oss/building-features/tanstack-router.md)). |
35-
| **TanStack Table** | Headless table/data-grid primitives | **Complement.** Renders from Rails-served data. |
36-
| **TanStack Start** | Full-stack React framework (Router + Vite + server functions) | **Substitute.** This is the layer that overlaps with Rails. |
36+
| What | What it is | Role for a Rails team |
37+
| ------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
38+
| **TanStack Query** | Client-side server-state cache (fetch, cache, invalidate) | **Complement.** Point it at a Rails JSON API. |
39+
| **TanStack Router** | Type-safe client router with data loading + search-param validation | **Complement.** Client-only works in OSS; SSR is a Pro feature (see [TanStack Router](../../oss/building-features/tanstack-router.md)). |
40+
| **TanStack Table** | Headless table/data-grid primitives | **Complement.** Renders from Rails-served data. |
41+
| **TanStack Start** | Full-stack React framework (TanStack Router + Vite/Nitro + server functions) | **Substitute.** This is the layer that overlaps with Rails. |
3742

3843
Adopting Query, Router, and Table does **not** require leaving Rails — React on Rails apps use them on
3944
top of a Rails backend today. The only part you are choosing _between_ is the framework: **TanStack
@@ -46,8 +51,8 @@ data access, authorization, persistence, background work, and rendering HTML for
4651
The two stacks supply that server very differently.
4752

4853
- **TanStack Start brings the _wiring_ for a server, and you supply the server.** Start is
49-
**client-first**: client-side interactivity is the default, and you opt into server-side rendering per
50-
route. Its server story is **server functions** — typed functions guaranteed to run server-side,
54+
**SSR-first**: routes are server-rendered by default, with fine-grained selective SSR to opt a route
55+
out (`ssr: false` / `'data-only'`, or SPA mode). Its server story is **server functions** — typed functions guaranteed to run server-side,
5156
callable from the client as if they were local. But Start ships **no database, ORM, or auth of its
5257
own**; it works with "any database, bring your own stack" (Drizzle is the common choice). You assemble
5358
the backend; Start types the boundary to it.
@@ -96,9 +101,9 @@ is solving a problem you have already solved, in a second language.
96101

97102
## Rendering and first paint
98103

99-
- **TanStack Start** is client-first with **opt-in, per-route SSR**. You choose SSR/SSG/CSR per route,
100-
which is flexible, but server rendering is something you turn on where you need it rather than the
101-
default.
104+
- **TanStack Start** is **SSR-first**: routes are server-rendered by default. It offers fine-grained
105+
**selective SSR** — opt a route out with `ssr: false` or `ssr: 'data-only'`, or use SPA mode — which
106+
is a genuine strength for tuning per-route rendering.
102107
- **React on Rails** server-renders React from Rails (via the Node renderer in Pro), and **React on
103108
Rails Pro** adds streaming SSR and RSC: the HTML shell streams immediately and server-rendered data
104109
streams in progressively. TanStack Router state can be SSR'd and hydrated via Pro
@@ -122,17 +127,17 @@ Rails you generate them. (Improving this out of the box is on the roadmap — ch
122127
> Marked "as of 2026" where a row reflects a current state rather than a permanent design choice. Both
123128
> ecosystems move quickly — check each project's release notes before treating a label as permanent.
124129
125-
| Capability | React on Rails (+ Pro) | TanStack Start |
126-
| --------------------------------- | --------------------------------------------------- | ----------------------------------- |
127-
| Client data cache (Query) | Yes — TanStack Query against Rails | Yes — TanStack Query |
128-
| Type-safe client routing (Router) | Yes — TanStack Router; SSR is Pro | Yes — built in (Router is the core) |
129-
| Headless tables (Table) | Yes — TanStack Table | Yes — TanStack Table |
130-
| Backend (DB, ORM, auth, jobs) | Rails, batteries included | Bring your own (e.g. Drizzle) |
131-
| Server-logic colocation | RSC (Pro) + Rails controllers | Server functions |
132-
| Typed client/server boundary | Generate types from Rails (as of 2026) | Built-in (TypeScript on both sides) |
133-
| Default rendering | Server-rendered (Rails); streaming SSR + RSC in Pro | Client-first; SSR opt-in per route |
134-
| Language(s) | Ruby + TypeScript | TypeScript end to end |
135-
| Hosting model | Your Rails app + a Node renderer process (Pro) | One Node (or Edge) server process |
130+
| Capability | React on Rails (+ Pro) | TanStack Start |
131+
| --------------------------------- | --------------------------------------------------- | --------------------------------------- |
132+
| Client data cache (Query) | Yes — TanStack Query against Rails | Yes — TanStack Query |
133+
| Type-safe client routing (Router) | Yes — TanStack Router; SSR is Pro | Yes — built in (Router is the core) |
134+
| Headless tables (Table) | Yes — TanStack Table | Yes — TanStack Table |
135+
| Backend (DB, ORM, auth, jobs) | Rails, batteries included | Bring your own (e.g. Drizzle) |
136+
| Server-logic colocation | RSC (Pro) + Rails controllers | Server functions |
137+
| Typed client/server boundary | Generate types from Rails (as of 2026) | Built-in (TypeScript on both sides) |
138+
| Default rendering | Server-rendered (Rails); streaming SSR + RSC in Pro | SSR by default; selective per-route SSR |
139+
| Language(s) | Ruby + TypeScript | TypeScript end to end |
140+
| Hosting model | Your Rails app + a Node renderer process (Pro) | One Node (or Edge) server process |
136141

137142
The pattern mirrors the framework-vs.-libraries split: **the TanStack client libraries are shared
138143
ground** — both stacks use Query, Router, and Table. The divergence is entirely in the **server tier**:
@@ -170,11 +175,11 @@ This page is about _architecture_, not selection. For the decision itself:
170175
"TanStack vs. React on Rails" is really two questions. The TanStack **client libraries** — Query,
171176
Router, and Table — are **complementary**: React on Rails apps use them on top of a Rails backend today.
172177
Only TanStack **Start**, the full-stack framework, is a **substitute**, and the substitution is
173-
specifically for the **server tier**. TanStack Start is client-first with opt-in SSR and a typed
174-
**server-function** transport, but it ships **no backend** — you bring the database, ORM, auth, and
175-
jobs. React on Rails keeps **Rails** as that backend, batteries included, with React as the view layer;
176-
React on Rails Pro adds streaming SSR and **React Server Components**, which deliver the same colocation
177-
benefit as server functions while keeping data access in Rails. Start wins on one language and a free
178+
specifically for the **server tier**. TanStack Start is SSR-first (server-rendered by default, with
179+
selective per-route SSR) and a typed **server-function** transport, but it ships **no backend** — you
180+
bring the database, ORM, auth, and jobs. React on Rails keeps **Rails** as that backend, batteries included, with React as the view layer;
181+
React on Rails Pro adds streaming SSR and **React Server Components**, which remove the extra `/api`
182+
round-trip for a view while keeping data access in Rails. Start wins on one language and a free
178183
end-to-end type boundary; React on Rails wins when you want a real backend — Rails — under your React,
179184
and would rather adopt the TanStack libraries on top of it than rebuild the backend in JavaScript.
180185

0 commit comments

Comments
 (0)