TanStack Router (v1+) reference for code-based routing, loaders, search params, navigation, link composition, route guards, and integration patterns. Use when working with files under src/ that import from '@tanstack/react-router', when creating or modifying routes/route trees, when designing data-loading via route loaders or beforeLoad, when adding type-safe Links/useNavigate/useParams/useSearch, when configuring RouterProvider or createRouter, or whenever the user mentions "tanstack router", "route loader", "useParams", "useNavigate", "search params", "beforeLoad", or "code-based routes". Also triggers for migration questions from react-router or other routers.
Reference docs split into focused sections. Read the section matching the task:
| File | When to use |
|---|---|
| api.md | API surface: every export, type, hook, component. Use when you need exact signatures (useNavigate, useRouterState, Link, redirect, createRoute, etc.). |
| routing.md | Route tree composition: createRootRoute, createRoute, addChildren, path params ($person), splats, layout routes, route options. |
| guide.md | Deep-dive patterns: authenticated routes, search params, data loading via loaders, code splitting, custom search-param serialization, navigation, redirect semantics. |
| installation.md | Setup: install command, RouterProvider mount, TypeScript Register augmentation. |
| setup-and-architecture.md | Architecture rationale, type-safety model, loader-vs-on-mount tradeoffs, comparison with other routers. |
import { createRootRoute, createRoute, createRouter, Outlet } from '@tanstack/react-router';
const rootRoute = createRootRoute({
component: () => <Outlet />,
});
const personRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/ic-dashboard/$person',
loader: ({ params }) => fetchPerson(params.person), // runs BEFORE render
component: PersonScreen,
});
const routeTree = rootRoute.addChildren([personRoute]);
export const router = createRouter({ routeTree });
declare module '@tanstack/react-router' {
interface Register { router: typeof router }
}function PersonScreen() {
const { person } = personRoute.useParams();
const data = personRoute.useLoaderData();
// ...
}const navigate = useNavigate();
navigate({ to: '/ic-dashboard/$person', params: { person: email } });<Link to="/ic-dashboard/$person" params={{ person: email }}>{name}</Link>beforeLoad: ({ context, location }) => {
if (!context.user) {
throw redirect({ to: '/login', search: { redirect: location.href } });
}
}const route = createRoute({
// ...
validateSearch: (search: Record<string, unknown>) => ({
page: Number(search.page ?? 1),
sort: (search.sort as 'asc' | 'desc') ?? 'asc',
}),
});
// In component:
const { page, sort } = route.useSearch();Prefer route loader over on-mount React Query for primary screen data:
isPending flashqueryClient.ensureQueryData(...) inside the loaderloader: ({ params, context: { queryClient } }) =>
queryClient.ensureQueryData(personQuery(params.person)),Then the component reads the same query via useSuspenseQuery(personQuery(person)) — cache hit guaranteed.
See guide.md "Data Loading" section for full pattern.
f4e28bd
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.