tanstack-router — Cursor rule: type-safe React routing
A Cursor rule that sets agent conventions for TanStack Router v1: file-based routes, typed params and loader-based data fetching.
.cursor/rules/tanstack-router.mdcWhat tanstack-router does
The rule tells the agent how to write client-side routing with TanStack Router v1 in a React app. Routes are declared with createFileRoute or createRootRoute, data loads inside loader instead of useEffect, and search params get a Zod schema through validateSearch. Internal navigation uses <Link>, never <a href>.
It ships with concrete patterns: the src/routes layout with dynamic segments like $postId and pathless groups, typed access via Route.useLoaderData() and Route.useParams(), and a TanStack Query hookup through queryClient.ensureQueryData. Auth guards live in beforeLoad with a redirect, and router context handles dependency injection.
The rule is scoped by globs — src/routes/**/*, src/routeTree.gen.ts, app.config.ts — so it fires on route files rather than the whole codebase. One thing to check before you rely on it: the examples assume file-based routing with @tanstack/router-vite-plugin, so a project with a hand-written route tree will need those snippets adapted.
What it helps with
- declare a typed route with a dynamic segment
- validate search params with Zod instead of reading
window.location.search - move data fetching out of
useEffectinto aloader - guard a section behind auth with a redirect to login
- wire the router to TanStack Query through context
Example prompts for the agent
- add a /posts/$postId route with a loader and component
- set up typed search params for the search page
- put an auth guard on /_auth/dashboard
How to install tanstack-router
Manually: put the files in place
.cursor/rules/tanstack-router.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/tanstack-router.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/tanstack-router.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/tanstack-router.mdManually: put the files in place
.clinerules/tanstack-router.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about tanstack-router
How do I install tanstack-router in Cursor?
Create .cursor/rules/tanstack-router.mdc in your project root and paste the rule content into it. Cursor picks it up automatically and applies it to files matching the globs.
What does this rule do?
It sets agent conventions for TanStack Router v1: file-based routing, typed params and loader data, Zod search validation, auth guards, and TanStack Query integration.
When does the rule apply?
It is bound to the globs src/routes/**/*, src/routeTree.gen.ts and app.config.ts, so it triggers on route files rather than the entire project.
Source text
tanstack-router.mdc · CC0-1.0
---
description: "Type-safe routing with TanStack Router v1 for React apps, including file-based routing, loaders, search params validation, auth guards, and TanStack Query integration"
globs: ["src/routes/**/*", "src/routeTree.gen.ts", "app.config.ts"]
alwaysApply: false
---
You are an expert in TanStack Router v1, React, TypeScript, and type-safe client-side routing.
## Core Principles
- TanStack Router is 100% type-safe — leverage TypeScript generics for params, search params, and loader data
- Prefer file-based routing with `@tanstack/router-vite-plugin` for scalability
- Always define routes with `createFileRoute` or `createRootRoute`
- Route data loading belongs in `loader` functions, not in component `useEffect`
- Search params are first-class — always define their schema with Zod for type safety
## File-Based Route Conventions
```
src/routes/
__root.tsx ← Root layout
index.tsx ← / route
posts/
index.tsx ← /posts
$postId.tsx ← /posts/:postId (dynamic)
_layout.tsx ← Layout route (no path segment)
_auth/ ← Pathless auth layout group
dashboard.tsx
```
## Route Definition
```tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
component: PostComponent,
errorComponent: ({ error }) => <ErrorBanner message={error.message} />,
pendingComponent: () => <PostSkeleton />,
})
function PostComponent() {
const post = Route.useLoaderData() // type-safe
const { postId } = Route.useParams() // type-safe
return <div>{post.title}</div>
}
```
## Type-Safe Search Params
- Always define search params with Zod and `validateSearch`
- Access with `Route.useSearch()` — never read `window.location.search` directly
```tsx
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,
})
```
## Navigation
- Use `<Link>` for internal navigation — never `<a href>`
- Always pass typed `params` and `search` — the compiler will catch mistakes
```tsx
<Link to="/posts/$postId" params={{ postId: '123' }}>View Post</Link>
```
## Loaders + TanStack Query Integration
```tsx
export const Route = createFileRoute('/posts')({
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(postsQueryOptions()),
component: PostsPage,
})
```
## Router Context for Dependency Injection
```tsx
// __root.tsx
interface RouterContext { queryClient: QueryClient; auth: AuthState }
export const Route = createRootRouteWithContext<RouterContext>()({ component: RootLayout })
// main.tsx
const router = createRouter({ routeTree, context: { queryClient, auth } })
```
## Auth Guards
```tsx
export const Route = createFileRoute('/_auth/dashboard')({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) throw redirect({ to: '/login' })
},
component: Dashboard,
})
```
## Performance
- Set `defaultPreload: 'intent'` on router for automatic prefetching on hover/focus
- Use `React.lazy` for route component code splitting
- Install `@tanstack/router-devtools` and render `<TanStackRouterDevtools />` in development
© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules