React logoReactv1INTERMEDIATE

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
Loading your progress

Setup & Installation

Installing and configuring TanStack Router

Installation

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

Router Setup

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

Root Route

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

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

Route Loader

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