Claude Code for TanStack Router — Workflow Guide
The Setup
You are building a React application with TanStack Router, the fully type-safe router that provides compile-time route validation, search param schemas, and file-based routing. Claude Code can generate routes and navigation, but it defaults to React Router v6 patterns that are structurally different.
What Claude Code Gets Wrong By Default
-
Uses React Router’s
<Route>JSX syntax. Claude writes<Route path="/users/:id" element={<UserPage />} />. TanStack Router defines routes as a tree usingcreateFileRouteorcreateRoutewith configuration objects. -
Ignores search parameter typing. Claude reads search params with
useSearchParams()returning untyped strings. TanStack Router validates search params with Zod or Valibot schemas, giving you typed, validated search parameters. -
Uses
useNavigate()with string paths. Claude writesnavigate('/users/123')with raw strings. TanStack Router’suseNavigate()takes typed route objects:navigate({ to: '/users/$id', params: { id: '123' } })with autocomplete. -
Creates a flat route structure. Claude puts all routes at the same level. TanStack Router uses nested route trees with parent layouts containing
<Outlet />for child routes, and file-based routing generates this tree from directory structure.
The CLAUDE.md Configuration
# TanStack Router Project
## Routing
- Router: TanStack Router (@tanstack/react-router)
- File-based: routes in src/routes/ directory
- Code gen: @tanstack/router-plugin for route tree generation
- Search params: validated with Zod schemas
## TanStack Router Rules
- Routes defined with createFileRoute('/path') in route files
- File structure = route structure (src/routes/users/$id.tsx)
- Search params typed via validateSearch with Zod schema
- Navigation: navigate({ to: '/path', params: {}, search: {} })
- Link component: <Link to="/users/$id" params={{ id }} />
- Loaders: route.loader for data fetching before render
- Layout routes: __root.tsx, _layout.tsx files
- Route tree auto-generated — never edit routeTree.gen.ts
## Conventions
- Root layout: src/routes/__root.tsx
- Index route: src/routes/index.tsx
- Dynamic params: $paramName in filename ($id.tsx)
- Layout groups: _layout/ directory for shared layouts
- Pending UI: route.pendingComponent for loading states
- Error handling: route.errorComponent per route
- Search params schemas colocated in route files
Workflow Example
You want to add a user detail page with search params for tab selection. Prompt Claude Code:
“Create a /users/$id route with TanStack Router. Add a validated search param for the active tab (profile, settings, billing) with a default of profile. Include a loader that fetches user data, and show a pending component during loading.”
Claude Code should create src/routes/users/$id.tsx using createFileRoute('/users/$id') with validateSearch using a Zod schema for { tab: z.enum(['profile', 'settings', 'billing']).default('profile') }, a loader that fetches user data with the $id param, a pendingComponent for loading state, and the main component accessing typed search params via useSearch().
Common Pitfalls
-
Editing the generated route tree. Claude modifies
routeTree.gen.tsdirectly. This file is auto-generated by the TanStack Router plugin — any changes are overwritten. Create routes by adding files tosrc/routes/, not by editing the generated tree. -
Missing the router plugin in build config. Claude creates route files but does not configure
@tanstack/router-pluginin the Vite or Webpack config. Without the plugin, the route tree is not generated and routes are not discovered. -
Using
useParamswithout the route context. Claude callsuseParams()in components that are not rendered inside the correct route. TanStack Router’suseParams()requires the component to be a child of the specific route — useRoute.useParams()for the route-specific typed version.