| | |

TanStack Router 16 ⚛️ CheatSheet

⏱️ Estimated read: 4 min | |

1. Installation & Setup

npm i @tanstack/react-router @tanstack/react-router-devtools
npm i -D @tanstack/router-plugin
// vite.config.ts
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
  plugins: [tanstackRouter({ target: 'react' }), react()],
})
// src/main.tsx
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 }
}

2. File-Based Routing Conventions

File NameURL Path
__root.tsxRoot layout
index.tsx/
about.tsx/about
users.$id.tsx/users/$id
posts.{-$month}.tsx/posts/{-$month} (optional)
$.tsx/$ (splat/catch-all)
_app.tsxPathless layout (not in URL)

3. Root Route (Layout)

// src/routes/__root.tsx
import { createRootRoute, Link, Outlet } from '@tanstack/react-router'

export const Route = createRootRoute({
  component: () => (
    <>
      <nav><Link to="/">Home</Link></nav>
      <Outlet />
    </>
  ),
})

4. Navigation (Link & useNavigate)

import { Link, useNavigate } from '@tanstack/react-router'

// Declarative
<Link to="/posts/$postId" params={{ postId: '123' }}>Post</Link>
<Link to="/search" search={{ page: 2 }}>Search</Link>

// Imperative
const navigate = useNavigate()
navigate({ to: '/dashboard', replace: true })

5. Path Parameters (useParams)

// src/routes/users.$id.tsx
export const Route = createFileRoute('/users/$id')({
  params: { parse: (p) => ({ id: Number(p.id) }) },
  component: UserProfile,
})

function UserProfile() {
  const { id } = Route.useParams() // id: number
  return <div>User: {id}</div>
}

6. Search Params (validateSearch)

import { z } from 'zod'

const schema = z.object({
  page: z.number().default(1),
  sort: z.enum(['name', 'date']).default('date'),
})

export const Route = createFileRoute('/posts')({
  validateSearch: schema,
  component: Posts,
})

function Posts() {
  const { page, sort } = Route.useSearch() // typed
  return <div>Page: {page}</div>
}

7. Data Loaders

export const Route = createFileRoute('/posts')({
  loader: async ({ params, request }) => {
    const url = new URL(request.url)
    const page = url.searchParams.get('page')
    return fetch(`/api/posts?page=${page}`).then((r) => r.json())
  },
  component: Posts,
})

function Posts() {
  const data = Route.useLoaderData()
  return <ul>{data.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
}

8. Pending States (Loading UI)

export const Route = createFileRoute('/posts')({
  loader: fetchPosts,
  pendingComponent: () => <p>Loading...</p>,
  pendingMs: 1000,
  pendingMinMs: 500,
})

9. Error Handling

export const Route = createFileRoute('/posts/$id')({
  loader: async ({ params }) => {
    const res = await fetch(`/api/posts/${params.id}`)
    if (res.status === 404) throw notFound()
    if (!res.ok) throw new Error('Failed')
    return res.json()
  },
  errorComponent: ({ error }) => <p>Error: {error.message}</p>,
  notFoundComponent: () => <p>404 Not Found</p>,
})

10. Layout Routes & Pathless Layouts

// src/routes/dashboard.tsx (Layout with URL)
export const Route = createFileRoute('/dashboard')({
  component: () => <div><Sidebar /><Outlet /></div>,
})

// src/routes/_app.tsx (Layout without URL)
export const Route = createFileRoute('/_app')({
  component: () => <div><Header /><Outlet /></div>,
})

11. Guards & Auth (beforeLoad)

export const Route = createFileRoute('/_authenticated')({
  beforeLoad: ({ context, location }) => {
    if (!context.auth.isAuthenticated) {
      throw redirect({ to: '/login', search: { redirect: location.href } })
    }
  },
  component: () => <Outlet />,
})

12. Forms & Mutations

export const Route = createFileRoute('/create')({
  action: async ({ request }) => {
    const formData = await request.formData()
    await fetch('/api/posts', { method: 'POST', body: formData })
    return redirect({ to: '/posts' })
  },
  component: NewPost,
})

function NewPost() {
  return <form method="post"><input name="title" /><button>Save</button></form>
}

13. Fetchers (In-place Mutations)

import { useFetcher } from '@tanstack/react-router'

function LikeButton() {
  const fetcher = useFetcher()
  return (
    <fetcher.Form method="post" action="/like">
      <button>{fetcher.state === 'submitting' ? '...' : 'Like'}</button>
    </fetcher.Form>
  )
}

14. TanStack Query Integration

import { queryOptions, useSuspenseQuery } from '@tanstack/react-query'

const postsQuery = queryOptions({
  queryKey: ['posts'],
  queryFn: () => fetch('/api/posts').then((r) => r.json()),
})

export const Route = createFileRoute('/posts')({
  loader: ({ context }) => context.queryClient.ensureQueryData(postsQuery),
  component: () => {
    const { data } = useSuspenseQuery(postsQuery)
    return <ul>{data.map((p) => <li key={p.id}>{p.title}</li>)}</ul>
  },
})

15. Testing

import { createMemoryHistory, createRouter } from '@tanstack/react-router'

const history = createMemoryHistory({ initialEntries: ['/posts'] })
const router = createRouter({ routeTree, history })
render(<RouterProvider router={router} />)
await router.load()
expect(await screen.findByText('Post 1')).toBeInTheDocument()

16. Server-Side Rendering (SSR)

// Server
const router = createRouter({ routeTree, history: createMemoryHistory({ initialEntries: [url] }) })
await router.load()
const html = renderToString(<RouterProvider router={router} />)
const dehydrated = router.dehydrate()

// Client
const router = createRouter({ routeTree, hydrationData: dehydrated })
hydrateRoot(document.getElementById('root'), <RouterProvider router={router} />)

17. Key Files

FilePurpose
src/routes/Directory for route files
src/routeTree.gen.tsGenerated route tree (ignore in lint)
src/main.tsxRouter creation & rendering
src/routes/__root.tsxRoot layout
vite.config.tsRouter plugin configuration

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!