Technology handbook
TanStack Router
Type-safe routes, loaders, search parameters, navigation, guards and code splitting.
- Topics
- 34
- Sections
- 5
Hooks
useNavigate
Navigate imperatively with typed params and search, from an event handler.
- The target route id is checked, so a deleted route breaks the build.
- Params and search are typed against that route's own definitions.
- Replace rather than push when the current entry should not return on back.
useParams
Read typed path parameters for the matched route.
- Parameters arrive already parsed, so no cast is needed at the call site.
- Reading from a route that does not declare the parameter is a type error.
- A strict option decides whether the hook reads this match or the nearest one.
useSearch
Read validated search parameters as typed state rather than parsing the query string.
- Search is validated state, not a string the component parses itself.
- Defaults are applied, so a missing parameter still has a usable value.
- This is where filters and pagination belong: shareable and restorable.
useRouter
Reach the router instance for imperative work such as invalidation or preloading.
- The instance is how imperative code invalidates or preloads a route.
- It reaches navigation outside a component tree, such as from an interceptor.
- Prefer the specific hooks where one exists, because they re-render precisely.
useRouterState
Observe pending navigations and the current location as state.
- A pending navigation is observable, so a global progress bar is possible.
- Reading the location as state keeps derived UI in step with the URL.
- Select a slice, or every navigation re-renders the subscriber.
useLoaderData
Read what the route's loader returned, already resolved before the component rendered.
- The data is already resolved, so the component has no loading branch.
- Its type comes from the loader, so a changed return shape breaks consumers.
- A parent layout's loader data is readable from the child's match.
useMatch and useMatches
Read one matched route, or the whole chain, for breadcrumbs and layout decisions.
- The chain of matches is what a breadcrumb trail is built from.
- A layout can read a child's match to decide what to render around it.
- Route-level metadata travels on the match, not in a separate lookup.
useRouteContext
Read the context a route built for itself and its children.
- Context is built in beforeLoad and inherited by every child route.
- It is the typed way to pass a session or a client into loaders.
- Each route can extend what it received without mutating the parent.
useBlocker
Stop a navigation while a form has unsaved changes, and let the user decide.
- A blocker intercepts in-app navigation before it commits.
- The reader gets a choice, rather than losing a half-finished form.
- A browser tab close needs a separate handler; the router cannot stop it.
useLinkProps
Build a custom link component that keeps preloading and active state.
- The props carry preloading, active state and the resolved href together.
- A design-system link can wrap them and stay a real anchor element.
- Hand-built hrefs lose type checking and the preloading behaviour.
Routing fundamentals
Route trees
Compose routes hierarchically so layouts and data nest the way the UI does.
- Nesting routes nests layouts, loaders and error boundaries together.
- A parent's data is loaded once and shared by every child beneath it.
- The tree is what makes a partial re-render on navigation possible.
File-based routing
Generate the route tree from files and keep the URL visible in the directory.
- The directory is the route table, so the URL is readable from the file tree.
- The generated tree is what carries the types into every hook.
- Generation runs in the dev server, so a new file is routable immediately.
Code-based routing
Declare routes explicitly when the structure is dynamic or shared.
- Explicit definitions suit routes built from configuration at runtime.
- The same route objects power both approaches underneath.
- It is also how a shared library ships routes into a host application.
Path parameters
Capture typed segments and read them without casting.
- A parameter is parsed into a typed value before any loader runs.
- Parsing and serialising can be customised for ids that are not strings.
- An invalid parameter can be rejected at the route rather than in the component.
Layout and pathless routes
Share UI or logic across children without adding a URL segment.
- A pathless route adds a wrapper without adding a URL segment.
- It is how a group of pages shares a guard or a shell.
- Grouping this way keeps the URL from growing folders that mean nothing.
Not-found and error routes
Handle a missing match and a thrown error at the right level of the tree.
- A not-found handler on a branch keeps the rest of the layout on screen.
- An error component catches what its own loader threw, not the whole app.
- Handling both at the root only is what produces a blank page on one bad id.
Data loading
Route loaders
Fetch before render so a route commits with its data already present.
- The route commits only when its data is ready, so no spinner flashes.
- Parent and child loaders run in parallel rather than in a waterfall.
- A loader throwing a redirect sends the reader elsewhere before render.
loaderDeps
Declare which search parameters a loader depends on so it reruns when they change.
- Declared dependencies are what tell the router to rerun the loader.
- Without them a change to a filter leaves the old data on screen.
- Keep the dependency object small; it is compared on every navigation.
Stale-while-revalidate
Serve cached route data immediately while refreshing it in the background.
- Cached route data renders immediately and refreshes behind the view.
- Staleness is configured per route, since not all data ages alike.
- Invalidating after a write is what forces the next visit to reload.
Preloading on intent
Start loading on hover or focus so the click feels instant.
- Hovering a link starts the loader before the click arrives.
- The preload is cached, so the navigation itself renders instantly.
- A delay threshold keeps a passing cursor from fetching every link.
Integrating with Query
Let the router await a query client prefetch instead of duplicating a cache.
- The loader awaits a prefetch and the component reads from the query cache.
- One cache then serves both, so there is nothing to keep in sync.
- Invalidation stays in the query client rather than being duplicated.
Pending and error components
Render a route's own pending and failure UI at the boundary that owns it.
- Each route owns the placeholder that replaces it while it loads.
- A pending threshold avoids a flash on a load that finishes quickly.
- A minimum display time stops the placeholder from blinking.
Search parameters
Search validation
Parse the query string into typed values with a schema and sensible defaults.
- A schema turns the query string into typed, defaulted values.
- Invalid parameters can be corrected or rejected before the loader runs.
- Validated search is what makes a filtered view a shareable URL.
Typed navigation
Move between routes with parameters the compiler checks.
- The compiler rejects a link to a route that needs a parameter you omitted.
- Renaming a route surfaces at every link that pointed at it.
- Relative navigation resolves against the current match, and is typed too.
Search middleware
Retain or strip parameters consistently as the reader navigates.
- Middleware decides which parameters survive a navigation.
- Keeping a filter across pages is a rule, not something each link repeats.
- It is also where a parameter is stripped once it no longer applies.
Structural sharing of search
Avoid rerenders when an unrelated part of the query string changes.
- Unchanged parts of the search object keep their references.
- A component reading one parameter is not re-rendered by another changing.
- It matters on screens where several controls write to the same URL.
Links and active state
Build links from route definitions and style the active match.
- Active state comes from the matched route, not from comparing strings.
- Exact and partial matching differ for a parent item in a navigation bar.
- The link renders a real anchor, so middle-click and open-in-new-tab work.
Navigation blocking
Warn before leaving a route with unsaved work.
- A guard on a dirty form prevents silent loss of work.
- The prompt should say what is unsaved, not just ask to confirm.
- Clear the block after a successful save or the warning outlives the edit.
Production concerns
Route guards
Redirect from beforeLoad when a route requires authentication or a role.
- beforeLoad runs before the loader, so a redirect costs no fetch.
- It can inspect context, which is where the session usually lives.
- The server must still authorise; a client guard only shapes navigation.
Router context
Pass shared dependencies, such as a client or a session, down the tree.
- Context is injected once at creation and typed throughout the tree.
- Loaders receive it, which keeps a client out of module-level state.
- A route can add to it for its children without touching the parent.
Lazy routes
Split route code so a bundle loads only when its route is visited.
- Splitting by route is the split that matches how people actually navigate.
- The critical part of a route can stay eager while its component is lazy.
- Preloading on intent hides the extra request behind the hover.
Scroll restoration
Restore position on back navigation without fighting the browser.
- Position is recorded per entry and restored on a back navigation.
- A forward navigation should start at the top, which is the opposite behaviour.
- A scroll container other than the window has to be named explicitly.
Server-side rendering
Render a matched route on the server and hydrate without a second load.
- Loaders run on the server and their results are streamed to the client.
- Hydration adopts that data, so no route refetches on first paint.
- A redirect thrown during a server load is a real HTTP redirect.
Devtools
Inspect matches, loader state and search parsing to explain a navigation.
- The panel shows the matched chain with each route's loader state.
- It explains why a loader reran by showing the dependencies that changed.
- Parsed search is visible there, which settles most validation questions.
Sources
- TanStack Router official documentation