Using TanStack Router
TanStack Router is a fully type-safe React router with built-in data loading, search param validation, and first-class TypeScript support. It's a strong choice when you want end-to-end type safety from your route definitions through to your components and search params.
React on Rails Pro supports TanStack Router SSR via react-on-rails-pro/tanstack-router.
This helper creates a render-function that handles both server-side rendering and client hydration/navigation.
TanStack Router SSR requires React on Rails Pro with the Node Renderer and
rendering_returns_promises = true in your Pro configuration. The async Node Renderer
uses TanStack Router's public router.load() API for reliable, maintainable SSR.
Client-side-only TanStack Router (without SSR) works with the open-source package - no special integration is needed since it's just a standard React app.
Support Model
- First-class TanStack Router SSR: React on Rails Pro only, via
react-on-rails-pro/tanstack-router - Server renderer: Pro Node Renderer with
rendering_returns_promises = true - ExecJS: intentionally not supported for TanStack Router SSR
- Client-only TanStack Router: works in OSS without any special helper
- React Router: remains the manual integration option; see Using React Router
Why Pro-Only
This guide intentionally avoids an ExecJS SSR path.
Synchronous SSR with TanStack Router pushes React on Rails toward private TanStack Router internals.
The Pro-only async path keeps the integration on TanStack Router's public router.load(),
router.dehydrate(), and router.hydrate() APIs, which is a much better long-term maintenance boundary.
Install
pnpm add @tanstack/react-router
Register a TanStack Router App
Create a render-function with createTanStackRouterRenderFunction and register it with React on Rails:
import ReactOnRails from 'react-on-rails-pro';
import { createTanStackRouterRenderFunction } from 'react-on-rails-pro/tanstack-router';
import {
RouterProvider,
createBrowserHistory,
createMemoryHistory,
createRouter,
} from '@tanstack/react-router';
import { routeTree } from '../routes/routeTree.gen';
const TanStackApp = createTanStackRouterRenderFunction(
{
createRouter: () => createRouter({ routeTree }),
// AppWrapper: ({ children }) => <MyProviders>{children}</MyProviders>, // optional
},
{
RouterProvider,
createMemoryHistory,
createBrowserHistory,
},
);
ReactOnRails.register({ TanStackApp });
Then render it from Rails:
<%= react_component("TanStackApp", props: { currentUserId: current_user&.id }, prerender: true) %>
How SSR + Hydration Works
On the server, the helper returns a server render hash:
{
renderedHtml: ReactElement,
clientProps: {
__tanstackRouterDehydratedState: { ... }
}
}
React on Rails then:
- Renders
renderedHtmlinto HTML. - Merges
clientPropsinto the client hydration payload generated byreact_component. - Hydrates TanStack Router on the client using the dehydrated router state.
Props Requirement
When using this helper with prerender: true, pass props: as a Ruby Hash or a JSON object string.
If you pass a JSON string that parses to a non-object value (like an array), React on Rails raises an error.
Pro Configuration
Ensure your React on Rails Pro initializer includes:
ReactOnRailsPro.configure do |config|
# TanStack Router SSR requires the Pro Node Renderer async path.
config.rendering_returns_promises = true
end
Compatibility
- Supported
@tanstack/react-routerversions:>=1.139.0 <2.0.0 - Keep
react-on-rails-proup to date when upgrading@tanstack/react-router.
Working Examples in This Repo
- Pro dummy app (async server rendering):
- Route + view:
react_on_rails_pro/spec/dummy/config/routes.rbreact_on_rails_pro/spec/dummy/app/views/tanstack_router/index.html.erb
- TanStack app entry:
react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/TanStackRouterAppAsync.jsx
- System test:
react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb
- Route + view: