TanStack Router 16 ⚛️ CheatSheet
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 Name | URL Path |
|---|---|
__root.tsx | Root layout |
index.tsx | / |
about.tsx | /about |
users.$id.tsx | /users/$id |
posts.{-$month}.tsx | /posts/{-$month} (optional) |
$.tsx | /$ (splat/catch-all) |
_app.tsx | Pathless 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
| File | Purpose |
|---|---|
src/routes/ | Directory for route files |
src/routeTree.gen.ts | Generated route tree (ignore in lint) |
src/main.tsx | Router creation & rendering |
src/routes/__root.tsx | Root layout |
vite.config.ts | Router plugin configuration |
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!