Rails 8 · React 19 · React on Rails Pro · TanStack Router

React Server Components on Rails, without moving your app to a JS server.

Keep Rails as the application server for auth, sessions, CSRF, validations, mailers, jobs, and Active Record. Add React on Rails Pro where server-rendered React and RSC need a Node rendering boundary. Use bare TanStack Router where the browser should own app navigation and URL state.

Demo login: demo@example.com / password

Rendering boundary

One Rails app, three deliberate surfaces

Public RSC

A TanStack route loader composes a Pro RSC payload from Rails; only explicit client islands hydrate.

Authenticated TanStack

TanStack Router, Query, and Table run inside Rails-owned full-page routes.

Classic Rails

Plain Rails CRUD remains available where a client app shell would add no value.

  • React Server Components
  • React on Rails Pro
  • TanStack Router
  • TanStack Query
  • TanStack Table
  • Rails 8
  • PostgreSQL
  • React 19
  • TypeScript
  • Tailwind v4
  • shadcn/ui
  • Rspack default
  • Webpack optional comparison

Why this stack

React where it changes the product. Rails where it already wins.

Inertia keeps Rails controllers close to pages by sending props to a client component tree. This starter chooses a different boundary: Rails remains the app server, while React on Rails Pro owns the server-rendered React and RSC boundary. That lets server components stay server-only instead of becoming another client page protocol.

No framework swap

No TanStack Start, Vite migration, Hotwire layer, or file-based routing requirement.

Server-only code stays server-only

RSC modules can await server data without shipping that implementation to the browser.

URL state belongs to TanStack

The dashboard table keeps filter, sort, and pagination in shareable browser URLs.

Rails still owns the app

Authentication, authorization boundaries, CSRF, model validation, mailers, and jobs stay in Rails.

Explore every surface

Each surface this starter ships is one click away, with a direct link to its source on GitHub. Authenticated routes open the sign-in page first.

RSC + TanStack

RSC showcase

A bare TanStack Router loader fetches a React on Rails Pro RSC payload from Rails and composes it beside client islands.

App shell

TanStack dashboard (sign in)

Authenticated Rails routes render a TanStack Router, Query, and Table dashboard through the React on Rails Pro Node renderer.

Data

Rails JSON API + Query (sign in)

Rails keeps persistence, validation, CSRF, filtering, sorting, and pagination. TanStack Query owns browser cache and invalidation.

Baseline

Classic Rails CRUD (sign in)

Conventional Rails forms and controller patterns remain available for CRUD screens that do not need a client app shell.

Accounts

Auth + email verification

Session auth, signup with email verification gating, password reset, mailers, and previews are already wired.

Profile

Settings (sign in)

Profile updates run from the TanStack dashboard while Rails still owns validation and the unverified-on-email-change gate.

Made for your AI agent

The repo ships an AGENTS.md playbook with reference patterns. Point Claude, Cursor, or Codex at the repo and paste one of these to learn, extend, or experiment.

Get oriented

Clone shakacode/react-on-rails-starter-tanstack and read AGENTS.md. Then explain how Rails routes /dashboard to DashboardController#show, how app/views/dashboard/show.html.erb renders DashboardApp, and how React on Rails Pro hands TanStack Router its SSR and hydration state.

Trace the RSC path

Walk me through the /rsc-showcase flow in this repo: app/controllers/rsc_showcase_controller.rb, app/views/rsc_showcase/show.html.erb, app/javascript/src/RscShowcase/ror_components/RscShowcaseApp.tsx, and the React on Rails Pro RSC payload route. Include how /hello_server remains the lower-level streaming reference.

Add a feature

In this repo, add a priority column to Project (enum: low, medium, high). Surface it as a sortable, URL-synced column in the TanStack table in DashboardApp.tsx, add server-side sorting in app/controllers/api/projects_controller.rb, and write request and Playwright specs following the existing patterns.

Add a new route

Add an authenticated TanStack route at /reports following the dashboard-props-controller and tanstack-route reference patterns in AGENTS.md. Pass Rails-owned props through DashboardController and render a summary built with TanStack Query.