Knowledge base from the official TanStack Router documentation (tanstack.com/router) — a fully type-safe router for React and Solid with first-class search-param state management, file-based and code-based routing, and built-in data loading. Use when building or debugging routing with createFileRoute/createRootRoute, wiring loaders/search-param validation, choosing file-based vs code-based routing, handling SSR/streaming, setting up route masking or navigation blocking, or integrating with TanStack Query.
Package: @tanstack/react-router (+ @tanstack/router-core, @tanstack/solid-router) | Chapters: 57 (14 Get Started + 41 Guides + 2 API) | Generated: 2026-08-25
file-based routing, search params, loaders, SSR, route masking, etc.; I find and read the matching chapterch010; I load that specific chapterWhen you ask about a topic not covered in Core Patterns below, I will read the relevant chapter file before answering.
Routing style: Default to file-based routing (routes under src/routes/, generated via the tanstackRouter bundler plugin or tsr CLI into routeTree.gen.ts). Reach for code-based routing (createRoute + getParentRoute + addChildren) only when filesystem-based generation genuinely doesn't fit; the docs explicitly discourage it for most apps since it needs more boilerplate for equivalent results.
Route file naming tokens: $param (dynamic segment), $ alone (splat/catch-all), _prefix (pathless layout, wraps children with no URL segment), _suffix (non-nested, breaks out of parent's component tree), -prefix (excluded from routing entirely, for colocated non-route files), (group) (organizational folder, invisible in the URL), {-$param} (optional path parameter), [x] (escapes a literal routing-significant character). Route matching always sorts by specificity (index > static, most-specific-first > dynamic, longest-first > splat) regardless of declaration order.
Type safety foundation: Always register the router instance once via TypeScript declaration merging immediately after createRouter(): declare module '@tanstack/react-router' { interface Register { router: typeof router } }. This single step is what makes Link, useNavigate, useParams, etc. type-safe project-wide without importing the router instance everywhere. Router-wide hooks used inside a specific route need a from hint (route ID/path, or Route.fullPath) to get precise narrowed types and catch runtime from/route mismatches; use strict: false for genuinely shared components that can't declare a from.
Data loading: Use a route's loader (not component-level useEffect) to fetch data in parallel with route matching. The router ships a built-in stale-while-revalidate cache (staleTime default 0, gcTime default 5 min) keyed on pathname plus loaderDeps (a deterministic function extracting only the search params the loader actually uses). For apps needing mutation APIs, persistence, or a cache shared beyond routing, coordinate an external library (TanStack Query, SWR, etc.) instead: call its prefetch/ensure API from loader without returning the data, and read it in the component via the library's own hook. Always create per-request external clients (e.g. new QueryClient()) inside createRouter/getRouter(), never at module scope, to avoid cross-request leakage on the server.
Search params are typed state, not strings: Validate every route's search params with validateSearch (ideally via a schema library adapter: Zod, Valibot, ArkType, Effect/Schema), preferring .catch()-style fallbacks over .default()-only so malformed URLs degrade gracefully. Read with Route.useSearch() (or useSearch({ from, strict: false }) outside a route's own component). Use search.middlewares (retainSearchParams, stripSearchParams, or custom) for cross-cutting behavior applied to every generated link, instead of repeating logic at each call site.
Navigation model: Every navigation API (Link, useNavigate, <Navigate>, router.navigate) shares the same from/to + params/search/hash/state shape (ToOptions/NavigateOptions/LinkOptions). Prefer <Link> for anything user-clickable (real <a href>, cmd/ctrl-click support, active-state styling); reserve useNavigate/router.navigate for side-effect-driven navigation. Wrap reusable navigation option objects in linkOptions() (not bare object literals) to catch type errors at definition time; wrap custom Link-like components with createLink() to keep full type safety and preload="intent" support.
Flow control via throwables: redirect() and notFound() are thrown (typically from beforeLoad/loader) to short-circuit rendering, mirroring each other's API (isRedirect/isNotFound). Guard an entire route subtree once, on the shared parent's beforeLoad (which always runs before any child's beforeLoad), rather than repeating checks per leaf route. Prefer throwing notFound() from loader over components, to keep loader data typed and avoid flicker. If using typescript-eslint's type-checked rulesets, allowlist Redirect/NotFoundError in only-throw-error rather than disabling it.
Router context for dependency injection: Type it with createRootRouteWithContext<T>(), supply initial values via createRouter({ context }), and extend it per-subtree by returning fields from a route's beforeLoad (merges into that route and its descendants only). Since hooks can't run inside beforeLoad/loader, bridge React-hook-derived values (like auth state) in by calling the hook in a component and passing the result through <RouterProvider context={...}>.
Performance levers: Enable autoCodeSplitting: true (or manual .lazy.tsx files) to split non-critical route config (component, errorComponent, pendingComponent, notFoundComponent) out of the main bundle, never split loader without strong reason since it adds a network round-trip before data fetching starts. Set defaultPreload: 'intent' for the highest-value, lowest-effort navigation-speed win. Use select on router-state hooks (useSearch, useRouterState) to subscribe to narrow state slices, pairing with structuralSharing: true when select computes a fresh object each call.
| # | Title | Key Concepts |
|---|---|---|
| ch001 | Overview | Inferred TypeScript, first-class search params, built-in cache |
| ch002 | Quick Start | @tanstack/cli create --router-only, file vs code-based routing |
| ch003 | Devtools | TanStackRouterDevtools, Floating/Fixed/Embedded modes |
| ch004 | Decisions on DX | getParentRoute, Register module declaration, no JSX routes |
| ch005 | Comparison | vs. React Router DOM and Next.js feature matrix |
| ch006 | FAQ | routeTree.gen.ts commit policy, root route rendering |
| # | Title | Key Concepts |
|---|---|---|
| ch007 | Manual Installation | __root.tsx, createRouter, RouterProvider |
| ch008 | With Vite | tanstackRouter Vite plugin, ignore-file config |
| ch009 | With Rspack | Rsbuild tools.rspack.plugins, Solid + Babel |
| ch010 | With Webpack | @tanstack/router-plugin/webpack |
| ch011 | With Esbuild | esbuild.context, manual dev/build/watch script |
| ch012 | With Router CLI | tsr generate/tsr watch, tsr.config.json |
| ch013 | Migrate from React Router | Link/useNavigate/useParams conversion |
| ch014 | Migrate from React Location | Route file recreation, module declaration |
| # | Title | Key Concepts |
|---|---|---|
| ch015 | Routing Concepts | Index/dynamic/splat/layout/pathless/non-nested routes |
| ch016 | Route Trees | Route tree = component tree, flat/directory/mixed styles |
| ch017 | Route Matching | Automatic specificity sorting, precedence order |
| ch018 | File-Based Routing | Directory vs flat routes, bundler integration |
| ch019 | Virtual File Routes | rootRoute/route/layout/physical, __virtual.ts |
| ch020 | Code-Based Routing | createRoute, addChildren, not recommended default |
| ch021 | File Naming Conventions | __root.tsx, ., $, _, -, (folder), [x] tokens |
| ch022 | URL Rewrites | Input/output rewrites, location.publicHref, composeRewrites |
| # | Title | Key Concepts |
|---|---|---|
| ch023 | Navigation | from/to, Link, useNavigate, useMatchRoute |
| ch024 | Link Options | linkOptions(), type-checked reusable nav objects |
| ch025 | Custom Link | createLink, UI library integration |
| ch026 | Path Params | $param, params.parse/stringify, prefix/suffix params |
| ch027 | Search Params | validateSearch, schema adapters, search middlewares |
| ch028 | Custom Search Param Serialization | parseSearchWith/stringifySearchWith, idempotency |
| ch029 | Route Masking | mask option, createRouteMask, unmaskOnReload |
| ch030 | Navigation Blocking | useBlocker, withResolver, enableBeforeUnload |
| ch031 | History Types | createBrowserHistory/createHashHistory/createMemoryHistory |
| ch032 | Scroll Restoration | scrollRestoration: true, useElementScrollRestoration |
| ch033 | Internationalization (i18n) | {-$locale}, rewrite option, Paraglide integration |
| # | Title | Key Concepts |
|---|---|---|
| ch034 | Code Splitting | Critical vs non-critical config, .lazy.tsx, getRouteApi |
| ch035 | Automatic Code Splitting | codeSplitGroupings, splitBehavior, defaultBehavior |
| ch036 | Data Loading | loader, loaderDeps, staleTime, gcTime, beforeLoad |
| ch037 | Deferred Data Loading | Unawaited promises, Await, streaming SSR |
| ch038 | External Data Loading | queryOptions, dehydrate/hydrate/Wrap, per-request stores |
| ch039 | Data Mutations | router.invalidate(), mutation keys, router.subscribe |
| ch040 | Preloading | Intent/viewport/render strategies, preloadStaleTime |
| ch041 | Document Head Management | head option, <HeadContent />, ScriptOnce |
| ch042 | SSR | Streaming vs non-streaming, createRequestHandler, RouterClient |
| ch043 | Render Optimizations | Structural sharing, select, structuralSharing |
| # | Title | Key Concepts |
|---|---|---|
| ch044 | Creating a Router | createRouter, Register declaration merging |
| ch045 | Outlets | <Outlet />, implicit outlet, root layout pattern |
| ch046 | Router Events | router.subscribe, onResolved, onRendered |
| ch047 | Type Safety | from hint, strict: false, TS performance narrowing |
| ch048 | Type Utilities | ValidateLinkOptions, double-overload pattern |
| ch049 | Router Context | createRootRouteWithContext, context merging, DI |
| ch050 | Not Found Errors | notFound(), notFoundComponent, notFoundMode |
| ch051 | Authenticated Routes | beforeLoad auth middleware, redirect-based protection |
| ch052 | Static Route Data | staticData, useMatches(), breadcrumbs |
| # | Title | Key Concepts |
|---|---|---|
| ch053 | TanStack Query Integration | setupRouterSsrQueryIntegration, useSuspenseQuery |
| # | Title | Key Concepts |
|---|---|---|
| ch054 | ESLint Plugin Router | flat/recommended, only-throw-error interop |
| ch055 | create-route Property Order Rule | Property inference order, autofixable |
| # | Title | Key Concepts |
|---|---|---|
| ch056 | Router API Reference | Functions, components, hooks, types index |
| ch057 | File-Based Routing API Reference | routesDirectory, routeToken, addExtensions |
Await component → ch037, ch056beforeLoad → ch036, ch049, ch050, ch051createLink → ch025createRouter → ch044, ch056staleTime/gcTime) → ch036, ch040select → ch043router.subscribe) → ch046from hint → ch047, ch048