TanStack Router
TanStack Router cheat sheet with type-safe routing, file-based routes, data loading, search params, and React code examples.
12 min read
tanstackrouterroutingreacttypescripttype-safedata-loading
Other React Sheets
Loading your progress
Setup & Installation
Installing and configuring TanStack Router
Install TanStack Router with bundler plugin
bash
npm install @tanstack/react-router
npm install -D @tanstack/router-plugin💡 Router plugin is required for file-based routing
⚡ Supports Vite, Webpack, Rspack, and Esbuild
🔍 Plugin auto-generates route tree and types
🎯 TypeScript v5.3+ recommended for best experience
installationsetupvite
Create and configure the router instance
typescript
import { createRouter, RouterProvider } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
const router = createRouter({ routeTree })
declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}
export default function App() {
return <RouterProvider router={router} />
}💡 Type registration enables full type inference
⚡ RouterProvider renders your route tree
🔍 routeTree.gen.ts is auto-generated by plugin
🎯 Set context for global data access in routes
routersetuptypescript
Define the root layout route
typescript
// src/routes/__root.tsx
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
export const Route = createRootRoute({
component: RootComponent,
})
function RootComponent() {
return (
<>
<div className="app">
<nav>{/* Navigation */}</nav>
<Outlet />
</div>
<TanStackRouterDevtools />
</>
)
}💡 __root.tsx must be in routes folder
⚡ <Outlet /> renders matched child routes
🔍 Wrap entire app with root layout
🎯 notFoundComponent handles 404 errors
rootlayoutoutlet
File-Based Routing
Using the filesystem to define routes
Use dots to represent route hierarchy
typescript
// File structure
routes/
__root.tsx
index.tsx # /
about.tsx # /about
posts.index.tsx # /posts
posts.$postId.tsx # /posts/:postId
posts.$postId.edit.tsx # /posts/:postId/edit
settings.profile.tsx # /settings/profile
settings.account.tsx # /settings/account💡 Dots (.) represent nesting levels
⚡ Best for deeply nested routes
🔍 No folder nesting required
🎯 Dollar sign ($) for dynamic params
flat-routesfile-basedstructure
Use folders to represent route hierarchy
typescript
// File structure
routes/
__root.tsx
index.tsx # /
about.tsx # /about
posts/
index.tsx # /posts
$postId.tsx # /posts/:postId
$postId/
index.tsx # /posts/:postId
edit.tsx # /posts/:postId/edit💡 Folders represent URL segments
⚡ Good for organizing related routes
🔍 index.tsx renders at folder path
🎯 Can mix with flat routes
directory-routesfile-basedfolders
Pathless layouts, catch-all, and index routes
typescript
// Pathless Layout (no URL segment)
routes/_auth.tsx # Layout wrapper
routes/_auth.login.tsx # /login (uses _auth layout)
routes/_auth.register.tsx # /register (uses _auth layout)
// Catch-all wildcard
routes/$.tsx # Matches any unmatched route
// Index route
routes/posts/index.tsx # Exact /posts match💡 Underscore (_) prefix for pathless layouts
⚡ $.tsx catches unmatched routes
🔍 $.tsx captures all remaining segments (splat), read via params._splat
🎯 index.tsx for exact path matches
layoutspathlesscatch-allwildcards
Navigation & Links
Navigating between routes
Type-safe navigation with Link
typescript
import { Link } from '@tanstack/react-router'
<Link to="/about">About</Link>
<Link to="/posts/$postId" params={{ postId: '123' }}>
View Post
</Link>
<Link
to="/search"
search={{ query: 'react', page: 1 }}
>
Search
</Link>💡 Fully type-safe to, params, and search
⚡ activeProps for styling active links
🔍 Automatic prefetching on hover
🎯 search function for merging params
linknavigationtype-safe
Programmatic navigation
typescript
import { useNavigate } from '@tanstack/react-router'
const navigate = useNavigate()
navigate({ to: '/posts' })
navigate({
to: '/posts/$postId',
params: { postId: '123' }
})💡 Use for programmatic navigation
⚡ Type-safe params and search
🔍 Supports relative paths (./edit, ..)
🎯 replace option for history control
navigateprogrammatichook
Redirect from loaders and actions
typescript
import { redirect } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard')({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login' })
}
},
})💡 throw redirect() to exit execution
⚡ Use in beforeLoad for auth guards
🔍 Can redirect from loader if data missing
🎯 Pass search.redirect for return URLs
redirectauthguards
Data Loading
Loading data with loaders and hooks
Define loader function to fetch data
typescript
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
return post
},
component: PostComponent,
})
function PostComponent() {
const post = Route.useLoaderData()
return <h1>{post.title}</h1>
}💡 Loader runs before component renders
⚡ Built-in SWR caching with staleTime
🔍 loaderDeps controls cache keys
🎯 abortController for request cancellation
loaderdatafetch
Access loader data in components
typescript
import { getRouteApi } from '@tanstack/react-router'
const routeApi = getRouteApi('/posts/$postId')
function PostComponent() {
const post = routeApi.useLoaderData()
return <div>{post.title}</div>
}💡 getRouteApi for components without route access
⚡ Fully type-safe loader data
🔍 Can access parent route loader data
🎯 Data available before component renders
useLoaderDatahookdata-access
Stream data and show content immediately
typescript
import { defer, Await } from '@tanstack/react-router'
export const Route = createFileRoute('/dashboard')({
loader: () => {
return defer({
critical: fetchCriticalData(), // Awaited
deferred: fetchSlowData(), // Streamed
})
},
component: Dashboard,
})
function Dashboard() {
const { critical, deferred } = Route.useLoaderData()
return (
<div>
<h1>{critical.title}</h1>
<Suspense fallback={<div>Loading...</div>}>
<Await promise={deferred}>
{(data) => <div>{data.content}</div>}
</Await>
</Suspense>
</div>
)
}💡 defer() for non-critical data streaming
⚡ Show page immediately with critical data
🔍 Use Suspense for loading states
🎯 Great for improving perceived performance
deferstreamingsuspense