tanstack router react
via PatrickJS/awesome-cursorrules
Type-safe file-based routing for React with TanStack Router v1, loaders, and search validation.
What is tanstack router react?
TanStack Router is a fully type-safe client-side router for React that uses file-based routing conventions, TypeScript generics for route params and search params, and loader functions for data fetching. Use this rule when building React applications that require scalable, type-checked routing with authentication guards, route preloading, and integrated data management.
- File-based routing with auto-generated route trees and dynamic segments ($param syntax)
- Type-safe route parameters, search params (with Zod validation), and loader data via TypeScript generics
- Route guards and authentication checks using beforeLoad hooks with redirect support
- Data loading via loader functions integrated with TanStack Query for caching and stale-time management
- Error handling with errorComponent, notFoundComponent, and pendingComponent for each route
- Route preloading and performance optimization with intent-based prefetching and code splitting
Applies to
File patterns this rule matches.
Rule definition (reference)
Source of truth, from the repository.
You are an expert in TanStack Router, React, TypeScript, and modern type-safe client-side routing.
TanStack Router + React Guidelines
Core Philosophy
- TanStack Router is 100% type-safe — leverage TypeScript generics for route params, search params, and loader data
- Prefer file-based routing for scalability; use code-based routing only for highly dynamic use cases
- Always define routes with
createFileRouteorcreateRootRoute— never use plain objects - Route data loading belongs in
loaderfunctions, not in componentuseEffect - Search params are first-class citizens — define their schema with Zod or Valibot for validation and type inference
Project Setup
- Use
@tanstack/react-routerwith Vite and the@tanstack/router-vite-pluginfor file-based routing - Enable
routeTree.gen.tsauto-generation — never manually edit this file - Structure routes under
src/routes/directory - Root layout goes in
src/routes/__root.tsx - Use
src/routes/index.tsxfor the home/index route
File-Based Route Conventions
src/routes/
__root.tsx ← Root layout (wraps all routes)
index.tsx ← / route
about.tsx ← /about route
posts/
index.tsx ← /posts route
$postId.tsx ← /posts/:postId (dynamic segment)
_layout.tsx ← Layout route (no path segment)
_auth/
login.tsx ← /login (grouped under auth layout)
(admin)/
dashboard.tsx ← /dashboard (pathless group)
Route Definition Patterns
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId) // fully typed params
},
component: PostComponent,
})
function PostComponent() {
const post = Route.useLoaderData() // type-safe loader data
const { postId } = Route.useParams() // type-safe params
return <div>{post.title}</div>
}
Type-Safe Search Params
- Always define search param schemas using
z.object()from Zod - Use
validateSearchoption on route definition - Access with
Route.useSearch()— never read rawwindow.location.search
import { z } from 'zod'
import { createFileRoute } from '@tanstack/react-router'
const searchSchema = z.object({
page: z.number().int().min(1).default(1),
q: z.string().optional(),
})
export const Route = createFileRoute('/search')({
validateSearch: searchSchema,
component: SearchPage,
})
function SearchPage() {
const { page, q } = Route.useSearch()
// ...
}
Navigation
- Use
<Link>from@tanstack/react-router— never<a href>for internal navigation - Use
useNavigate()for programmatic navigation - Always pass typed
paramsandsearchto Link — the compiler will catch mistakes
import { Link, useNavigate } from '@tanstack/react-router'
// Declarative
<Link to="/posts/$postId" params={{ postId: '123' }}>View Post</Link>
// Programmatic
const navigate = useNavigate()
navigate({ to: '/posts/$postId', params: { postId: post.id } })
Loaders & Data Fetching
- Use
loaderfor data that must be available before render (no loading spinners for critical data) - Integrate with TanStack Query by using
ensureQueryDatainside loaders for caching - Use
staleTimeon loaders to avoid redundant fetches during navigation - Return plain serializable data from loaders — no class instances
export const Route = createFileRoute('/posts')({
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(postsQueryOptions()),
component: PostsPage,
})
Error Handling
- Define
errorComponenton routes to handle loader or render errors - Use
notFoundComponentfor 404 states within a route subtree - Use
pendingComponentfor showing skeletons/spinners during data loading
export const Route = createFileRoute('/posts/$postId')({
loader: fetchPost,
errorComponent: ({ error }) => <ErrorBanner message={error.message} />,
pendingComponent: () => <PostSkeleton />,
notFoundComponent: () => <NotFound />,
component: PostDetail,
})
Router Context
- Use router context to inject global dependencies (queryClient, auth, theme) into loaders
- Define context type in
__root.tsxand pass it when creating the router
// __root.tsx
import { createRootRouteWithContext } from '@tanstack/react-router'
interface RouterContext {
queryClient: QueryClient
auth: AuthState
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: RootLayout,
})
// main.tsx
const router = createRouter({
routeTree,
context: { queryClient, auth },
})
Route Guards / Auth
- Use
beforeLoadfor authentication checks — redirect to login if unauthenticated - Never put auth logic inside components — handle it at the routing layer
export const Route = createFileRoute('/_auth/dashboard')({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login' })
}
},
component: Dashboard,
})
Performance
- Use
preloadon<Link>to trigger loader prefetching on hover/focus - Set
defaultPreload: 'intent'on the router for automatic preloading - Use
gcTimeandstaleTimeon loaders to tune cache behavior - Lazy-load route components with
React.lazyfor code splitting
DevTools
- Install
@tanstack/router-devtoolsand render<TanStackRouterDevtools />in development - Use devtools to inspect route tree, active matches, loader data, and search params
Testing
- Use
createMemoryHistoryandcreateRouterto create isolated router instances in tests - Wrap components under test with
<RouterProvider router={testRouter} /> - Mock loaders by providing fake context values
Related rules
Full-stack React framework with type-safe server functions, file-based routing, and streaming via TanStack Router + Vinxi.
Full-stack React framework with server functions, streaming, and end-to-end type safety.
Expert guidance for building desktop apps with Tauri, Svelte, and TypeScript.
Best practices and conventions for building Temporal.io workflows and activities in Python.
TensorFlow and deep learning best practices for building, training, and deploying neural networks
Create standardized TestRail test cases with clear structure, preconditions, and expected results.
