| name | router-core |
| description | TanStack Router expertise for file-based routing, route trees, auth guards, loaders, search params, navigation, code splitting, type safety, and error boundaries. Triggers when working with routes, createFileRoute, createRootRouteWithContext, beforeLoad, Link, useNavigate, or any @tanstack/react-router API. |
| user-invocable | false |
TanStack Router
CRITICAL: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
CRITICAL: CLIENT-FIRST. Loaders run on the client by default. Do not confuse with Next.js/Remix.
CRITICAL: createFileRoute path string must match the file path exactly — the Vite plugin manages this, do not edit manually.
Current Project Context
Stack: TanStack Router v1 (file-based) + TanStack Query + Supabase auth
Router setup (src/router.tsx):
export function getRouter() {
return createTanStackRouter({
routeTree,
context: getContext(),
scrollRestoration: true,
defaultPreload: "intent",
defaultPreloadStaleTime: 0,
})
}
declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof getRouter>
}
}
Root route context (src/routes/__root.tsx):
interface RouterContext {
queryClient: QueryClient
}
export const Route = createRootRouteWithContext<RouterContext>()({
beforeLoad: async ({ context, location }) => {
const user = await context.queryClient.ensureQueryData(userQueryOptions)
if (!user && !location.pathname.startsWith("/auth")) {
throw redirect({ to: "/auth/sign-in" })
}
return { user }
},
})
Auth pattern: Global auth guard in root beforeLoad. Auth routes live under /auth/*. Protected routes anywhere else — the root guard redirects unauthenticated users to /auth/sign-in.
Route tree (auto-generated at src/routeTree.gen.ts — never edit):
/ → src/routes/index.tsx
/auth → src/routes/auth/route.tsx (layout)
/auth/sign-in, /auth/sign-up, /auth/forgot-password
/update-password
/account/profile
Imports: Use #/ alias for src/ (e.g. #/components/ui/button, #/lib/supabase/data/auth)
Decision Tree
Adding/reading URL query params? → rules/search-params.md
Dynamic URL segments (/posts/$id)? → rules/path-params.md
Creating links or navigating programmatically? → rules/navigation.md
Fetching data for a route? → rules/data-loading.md
Protecting routes / auth redirects? → rules/auth-and-guards.md
Reducing bundle size per route? → rules/code-splitting.md
404 pages or error boundaries? → rules/not-found-and-errors.md
TypeScript issues with router types? → rules/type-safety.md
SSR / hydration? → rules/ssr.md
Critical Rules
Route files always export Route
import { createFileRoute } from "@tanstack/react-router"
export const Route = createFileRoute("/account/profile")({
component: ProfilePage,
})
beforeLoad for guards, loader for data
beforeLoad — auth checks, redirects, context enrichment. Runs before loader.
loader — fetch data for the route. Use context.queryClient.ensureQueryData() to integrate with TanStack Query.
export const Route = createFileRoute("/account/profile")({
beforeLoad: ({ context }) => {
if (!context.user) throw redirect({ to: "/auth/sign-in" })
},
loader: ({ context }) =>
context.queryClient.ensureQueryData(profileQueryOptions(context.user.id)),
component: ProfilePage,
})
redirect() must be thrown
throw redirect({ to: "/auth/sign-in" })
redirect({ to: "/auth/sign-in" })
Redirects inside try/catch need isRedirect
import { isRedirect } from "@tanstack/react-router"
beforeLoad: async ({ context }) => {
try {
await validateSession()
} catch (e) {
if (isRedirect(e)) throw e
throw redirect({ to: "/auth/sign-in" })
}
}
Access route data with route-scoped hooks
function ProfilePage() {
const data = Route.useLoaderData()
const { user } = Route.useRouteContext()
const params = Route.useParams()
const search = Route.useSearch()
}
Pathless layout routes use _ prefix
src/routes/_authenticated.tsx → layout, no URL segment
src/routes/_authenticated/dashboard.tsx → URL: /dashboard
Adding a New Route
- Create
src/routes/<path>.tsx
- Export
Route via createFileRoute('<path>')({...})
- The Vite plugin auto-updates
src/routeTree.gen.ts
- Never edit
routeTree.gen.ts manually
Detailed Rules