Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tanstack/router/llms.txt
Use this file to discover all available pages before exploring further.
Routes are the building blocks of your application’s navigation. Each route defines a path pattern, data loading logic, and components to render.
Creating Routes
Routes are created using the createRoute function:
import { createRoute } from '@tanstack/react-router'
import { rootRoute } from './root'
const aboutRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/about',
component: AboutComponent,
})
Root Route
Every route tree starts with a root route:
import { createRootRoute } from '@tanstack/react-router'
const rootRoute = createRootRoute({
component: () => (
<div>
<nav>{/* Navigation */}</nav>
<Outlet /> {/* Child routes render here */}
</div>
),
})
Route Options
Path Configuration
The path pattern to match. Can include parameters:path: '/posts/$postId' // Path parameter
path: '/files/$' // Wildcard
path: '/posts/{-$postId}' // Optional parameter
Custom route ID instead of using the path. Useful for routes without paths.
Components
The component to render when this route matches.component: () => <div>About Page</div>
Component shown while the route is loading data.pendingComponent: () => <div>Loading...</div>
errorComponent
React.ComponentType<ErrorComponentProps>
Component shown when an error occurs during loading or rendering.errorComponent: ({ error, reset }) => (
<div>
<p>Error: {error.message}</p>
<button onClick={reset}>Try Again</button>
</div>
)
Component shown when a child route is not found.notFoundComponent: () => <div>Page not found</div>
Search Parameter Validation
Function or validator to parse and validate search parameters.validateSearch: (search) => ({
page: Number(search.page) || 1,
filter: search.filter as string | undefined,
})
Path Parameter Parsing
Transform path parameters from strings to typed values.params: {
parse: (params) => ({
postId: Number(params.postId),
}),
}
Transform typed parameters back to strings for URL generation.params: {
stringify: (params) => ({
postId: String(params.postId),
}),
}
Data Loading
Context
Provide data to child routes and loaders:
const userRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/user',
context: ({ location }) => ({
userId: getUserIdFromLocation(location),
}),
})
Before Load
Run async code before the route loads:
const protectedRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/dashboard',
beforeLoad: async ({ context, location }) => {
if (!context.auth.isAuthenticated) {
throw redirect({
to: '/login',
search: { redirect: location.href },
})
}
},
})
Loader
Fetch data for the route:
const postRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts/$postId',
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
return { post }
},
})
Access loader data in components:
function PostComponent() {
const { post } = useLoaderData({ from: '/posts/$postId' })
return <div>{post.title}</div>
}
Loader Dependencies
Declare additional dependencies for cache keys:
const postsRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts',
loaderDeps: ({ search }) => ({
page: search.page,
filter: search.filter,
}),
loader: async ({ deps }) => {
const posts = await fetchPosts({
page: deps.page,
filter: deps.filter,
})
return { posts }
},
})
Caching Options
Time in milliseconds before cached data is considered stale.staleTime: 5000 // 5 seconds
Time in milliseconds before unused cached data is garbage collected.gcTime: 30 * 60 * 1000 // 30 minutes
How long preloaded data stays fresh.
How long preloaded data is cached.
Pending State
Delay in milliseconds before showing pending component.pendingMs: 500 // Show after 500ms
Minimum time in milliseconds to show pending component once displayed.
Lifecycle Hooks
onEnter
Called when a route match enters the active matches:
const route = createRoute({
getParentRoute: () => rootRoute,
path: '/analytics',
onEnter: (match) => {
trackPageView(match.pathname)
},
})
onStay
Called when a route match stays in active matches during navigation:
onStay: (match) => {
console.log('Route stayed active:', match.routeId)
}
onLeave
Called when a route match leaves the active matches:
onLeave: (match) => {
cleanupResources(match)
}
Lazy Loading
Split route components into separate bundles:
const postRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts/$postId',
}).lazy(() => import('./post.lazy').then(d => d.postLazyRoute))
In post.lazy.tsx:
import { createLazyRoute } from '@tanstack/react-router'
export const postLazyRoute = createLazyRoute('/posts/$postId')({
component: PostComponent,
})
SSR Configuration
ssr
boolean | 'data-only'
default:"true"
Control server-side rendering behavior:
true - Full SSR
false - Client-only
'data-only' - SSR data but not component
Head
Define meta tags, links, and scripts:
const postRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts/$postId',
head: ({ loaderData }) => ({
meta: [
{ title: loaderData.post.title },
{ name: 'description', content: loaderData.post.excerpt },
{ property: 'og:image', content: loaderData.post.image },
],
links: [
{ rel: 'canonical', href: `/posts/${loaderData.post.id}` },
],
}),
})
Set HTTP response headers:
headers: async ({ loaderData }) => ({
'Cache-Control': 'public, max-age=3600',
'X-Custom-Header': loaderData.customValue,
})
Error Handling
Error Component
const route = createRoute({
getParentRoute: () => rootRoute,
path: '/posts/$postId',
errorComponent: ({ error, reset }) => (
<div>
<h1>Error Loading Post</h1>
<p>{error.message}</p>
<button onClick={reset}>Retry</button>
</div>
),
})
onError Hook
onError: (error) => {
logErrorToService(error)
}
Redirects
Redirect from a route using the redirect helper:
import { redirect } from '@tanstack/react-router'
const oldRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/old-path',
beforeLoad: () => {
throw redirect({ to: '/new-path' })
},
})
Or use the route’s built-in redirect method:
const postRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/posts/$postId',
beforeLoad: ({ params }) => {
if (!isValidPostId(params.postId)) {
throw postRoute.redirect({ to: '/posts' })
}
},
})
Next Steps
Loaders
Deep dive into data loading patterns
Type Safety
Configure end-to-end type safety
Navigation
Navigate between routes programmatically
Path Params
Extract and validate path parameters