Skip to main content

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.

TanStack Router provides comprehensive type safety across your entire routing layer, from route definitions to navigation and data access.

Route Type Registration

Register your route tree for global type inference:
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

const router = createRouter({ routeTree })

// Register router type globally
declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}
Now all hooks and components have type information.

File-Based Routes

Generate type-safe routes from your file structure:
npx @tanstack/router-cli generate
This creates:
  • Type definitions for all routes
  • Global route type registration
  • Autocomplete for paths and params

Route File

// routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    // params.postId is typed as string
    const post = await fetchPost(params.postId)
    return { post }
  },
})

function PostComponent() {
  const { post } = Route.useLoaderData()
  // post is fully typed
  return <h1>{post.title}</h1>
}

Type-Safe Parameters

Path Parameters

Path params are automatically inferred:
const postRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts/$postId',
  // params.postId is string
})

function Component() {
  // Type-safe param access
  const { postId } = useParams({ from: '/posts/$postId' })
  //     ^? string
}

Parsed Parameters

Transform params with type safety:
const postRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts/$postId',
  params: {
    parse: (params) => ({
      postId: Number(params.postId),
    }),
    stringify: (params) => ({
      postId: String(params.postId),
    }),
  },
})

function Component() {
  const { postId } = useParams({ from: '/posts/$postId' })
  //     ^? number
  
  const next = postId + 1 // Type-safe arithmetic
}

Search Parameters

Define search param types with validators:
import { z } from 'zod'
import { zodValidator } from '@tanstack/zod-adapter'

const searchSchema = z.object({
  page: z.number().min(1).default(1),
  filter: z.enum(['all', 'active', 'completed']).default('all'),
  sort: z.enum(['date', 'title']).optional(),
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts',
  validateSearch: zodValidator(searchSchema),
})

function Component() {
  const search = useSearch({ from: '/posts' })
  //    ^? { page: number; filter: 'all' | 'active' | 'completed'; sort?: 'date' | 'title' }
}

Type-Safe Navigation

Links are fully type-checked:
<Link
  to="/posts/$postId"
  params={{ postId: 123 }} // Type error if wrong type
  search={{ page: 1 }}     // Type error if invalid search params
>
  View Post
</Link>
Invalid paths cause compile errors:
// ❌ Type error: "/invalid" is not a valid route
<Link to="/invalid">Invalid</Link>
Programmatic navigation is type-safe:
function Component() {
  const navigate = useNavigate()
  
  const goToPost = async () => {
    await navigate({
      to: '/posts/$postId',
      params: { postId: 123 }, // Fully typed
      search: { page: 1 },     // Validated against schema
    })
  }
}

From Parameter

Specify source route for relative navigation:
function Component() {
  // Type-safe relative navigation
  return (
    <Link from="/posts/$postId" to="../edit">
      Edit Post
    </Link>
  )
}

Type-Safe Data Access

Loader Data

Loader return types are inferred:
const postRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts/$postId',
  loader: async ({ params }) => {
    const post = await fetchPost(params.postId)
    const author = await fetchAuthor(post.authorId)
    return { post, author }
  },
})

function Component() {
  const { post, author } = useLoaderData({ from: '/posts/$postId' })
  //     ^? { post: Post; author: Author }
  
  return <h1>{post.title} by {author.name}</h1>
}

Context

Route context is fully typed:
const rootRoute = createRootRouteWithContext<{
  auth: AuthContext
}>()({
  component: () => <Outlet />,
})

const protectedRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/dashboard',
  beforeLoad: ({ context }) => {
    // context.auth is typed
    if (!context.auth.isAuthenticated) {
      throw redirect({ to: '/login' })
    }
  },
})

Strict Mode

Strict Params

Enable strict parameter typing:
function Component() {
  // Strict: Only params from this specific route
  const params = useParams({ from: '/posts/$postId', strict: true })
  //    ^? { postId: string }
  
  // Loose: Union of params from all routes
  const params = useParams({ strict: false })
  //    ^? { postId?: string; userId?: string; ... }
}
Strictly type search parameters:
const router = createRouter({
  routeTree,
  search: {
    strict: true, // Remove unknown search params
  },
})
With strict mode, only params defined in validateSearch are allowed.

Type Inference

Route by ID

Access route types by ID:
import type { RouteById } from '@tanstack/react-router'

type PostRoute = RouteById<typeof router.routeTree, '/posts/$postId'>
type PostParams = PostRoute['types']['allParams']
//   ^? { postId: string }

Route by Path

Access route types by path:
import type { RouteByPath } from '@tanstack/react-router'

type PostRoute = RouteByPath<typeof router.routeTree, '/posts/$postId'>

All Params

Get union of all route params:
import type { AllParams } from '@tanstack/react-router'

type Params = AllParams<typeof router.routeTree>
//   ^? { postId?: string; userId?: string; ... }

Router Context Type

Define context type for dependency injection:
interface MyRouterContext {
  auth: {
    isAuthenticated: boolean
    userId: string | null
  }
  queryClient: QueryClient
}

const rootRoute = createRootRouteWithContext<MyRouterContext>()({
  component: () => <Outlet />,
})

const router = createRouter({
  routeTree,
  context: {
    auth: getAuth(),
    queryClient: new QueryClient(),
  },
})
All routes inherit this context with full typing.

Type Helpers

ParsePathParams

Extract param types from path pattern:
import type { ParsePathParams } from '@tanstack/react-router'

type Params = ParsePathParams<'/posts/$postId/comments/$commentId'>
//   ^? { postId: string; commentId: string }

ResolveFullSearchSchema

Resolve complete search schema including parent routes:
import type { ResolveFullSearchSchema } from '@tanstack/react-router'

type Search = ResolveFullSearchSchema<
  typeof parentRoute,
  typeof searchValidator
>

MakeRouteMatch

Create a route match type:
import type { MakeRouteMatch } from '@tanstack/react-router'

type PostMatch = MakeRouteMatch<typeof postRoute>

Generic Components

Build reusable type-safe components:
function RouteTitle<TRoute extends AnyRoute>({
  from,
}: {
  from: TRoute['id']
}) {
  const data = useLoaderData({ from })
  return <h1>{data.title}</h1>
}

// Usage
<RouteTitle from="/posts/$postId" />

TSConfig Setup

Enable strict mode for best type safety:
{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true,
    "moduleResolution": "bundler",
    "types": ["@tanstack/react-router"]
  }
}

Type Errors

Common Issues

Missing Router Registration

// ❌ Hooks have loose types
const params = useParams()

// ✅ Register router globally
declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}

Wrong From Parameter

// ❌ Type error: route doesn't exist
const data = useLoaderData({ from: '/wrong/path' })

// ✅ Use correct route ID
const data = useLoaderData({ from: '/posts/$postId' })

Invalid Navigation

// ❌ Type error: wrong param type
<Link to="/posts/$postId" params={{ postId: '123' }} />

// ✅ Use correct type after parsing
<Link to="/posts/$postId" params={{ postId: 123 }} />

Type Generation

Manual Generation

npx @tanstack/router-cli generate

Watch Mode

npx @tanstack/router-cli watch

In Package Scripts

{
  "scripts": {
    "dev": "tanstack-router-cli watch & vite",
    "build": "tanstack-router-cli generate && vite build"
  }
}

Best Practices

Register your router type globally for complete type inference across your app.
Define search parameters with Zod, Valibot, or ArkType for runtime validation and type safety.
Use strict: true and strictNullChecks: true in tsconfig.json for maximum type safety.
Always specify from in hooks for route-specific types instead of loose union types.
Transform path params from strings to typed values using params.parse for better DX.

Next Steps

Search Params

Type-safe search parameter validation

Path Params

Type-safe path parameter parsing

Loaders

Type-safe data loading

Routes

Configure route type inference