Skip to main content
This quickstart guide will help you create a fully functional router-based React application in under 5 minutes.

Prerequisites

Before starting, make sure you have:
  • Node.js 20.19 or higher installed
  • A React application set up (or create one with Vite)
  • TanStack Router installed (see Installation)

Step 1: Create Your First Routes

Let’s build a simple application with a home page and an about page using code-based routing.
1
Import the Router Dependencies
2
Start by importing the necessary functions from TanStack Router:
3
import React from 'react'
import ReactDOM from 'react-dom/client'
import {
  Link,
  Outlet,
  RouterProvider,
  createRootRoute,
  createRoute,
  createRouter,
} from '@tanstack/react-router'
4
Create the Root Route
5
The root route serves as the layout wrapper for all other routes. It typically contains navigation and an <Outlet /> where child routes render:
6
const rootRoute = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">
          Home
        </Link>
        <Link to="/about" className="[&.active]:font-bold">
          About
        </Link>
      </div>
      <hr />
      <Outlet />
    </>
  ),
})
7
The <Outlet /> component renders the matched child route’s component. This enables nested layouts.
8
Create the Index Route
9
The index route renders at the root path (/):
10
const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/',
  component: function Index() {
    return (
      <div className="p-2">
        <h3>Welcome Home!</h3>
      </div>
    )
  },
})
11
Create the About Route
12
Add an about page at /about:
13
const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/about',
  component: function About() {
    return <div className="p-2">Hello from About!</div>
  },
})
14
Build the Route Tree
15
Combine your routes into a tree structure:
16
const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
17
Create the Router Instance
18
Create the router with your route tree and optional configuration:
19
const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  scrollRestoration: true,
})
20
The defaultPreload: 'intent' option preloads routes when users hover over links, creating a snappier experience.
21
Register the Router for Type-Safety
22
Register your router type for full TypeScript inference:
23
declare module '@tanstack/react-router' {
  interface Register {
    router: typeof router
  }
}
24
This declaration enables autocomplete for route paths, params, and search parameters throughout your application.
25
Render the Application
26
Finally, render your app with the RouterProvider:
27
const rootElement = document.getElementById('app')!

if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement)
  root.render(<RouterProvider router={router} />)
}

Complete Example

Here’s the full code for reference:
import React from 'react'
import ReactDOM from 'react-dom/client'
import {
  Link,
  Outlet,
  RouterProvider,
  createRootRoute,
  createRoute,
  createRouter,
} from '@tanstack/react-router'

const rootRoute = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">
          Home
        </Link>
        <Link to="/about" className="[&.active]:font-bold">
          About
        </Link>
      </div>
      <hr />
      <Outlet />
    </>
  ),
})

const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/',
  component: function Index() {
    return (
      <div className="p-2">
        <h3>Welcome Home!</h3>
      </div>
    )
  },
})

const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/about',
  component: function About() {
    return <div className="p-2">Hello from About!</div>
  },
})

const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])

const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  scrollRestoration: true,
})

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

const rootElement = document.getElementById('app')!
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement)
  root.render(<RouterProvider router={router} />)
}

Step 2: Add Data Loading

TanStack Router can load data before rendering routes. Let’s add a loader to fetch posts:
import { createRoute } from '@tanstack/react-router'

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/posts',
  loader: async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts')
    return response.json()
  },
  component: function Posts() {
    const posts = postsRoute.useLoaderData()
    
    return (
      <div className="p-2">
        <h3>Posts</h3>
        <ul>
          {posts.map((post: any) => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      </div>
    )
  },
})
Loaders run before the route component renders, ensuring data is ready when your component mounts.

Step 3: Add Path Parameters

Create dynamic routes with type-safe path parameters:
const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
  loader: async ({ params }) => {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts/${params.postId}`
    )
    return response.json()
  },
  component: function Post() {
    const post = postRoute.useLoaderData()
    
    return (
      <div className="p-2">
        <h4>{post.title}</h4>
        <p>{post.body}</p>
      </div>
    )
  },
})

Step 4: Add DevTools (Optional)

Install and add the DevTools for debugging:
main.tsx
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'

const rootRoute = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        {/* navigation */}
      </div>
      <hr />
      <Outlet />
      <TanStackRouterDevtools position="bottom-right" />
    </>
  ),
})
DevTools are automatically tree-shaken in production builds, so you can safely include them in your root route.

Type-Safe Navigation

TanStack Router provides full type-safety for navigation:
import { Link, useNavigate } from '@tanstack/react-router'

function MyComponent() {
  const navigate = useNavigate()
  
  return (
    <div>
      {/* Type-safe Link component */}
      <Link to="/posts/$postId" params={{ postId: '1' }}>
        View Post 1
      </Link>
      
      {/* Programmatic navigation */}
      <button
        onClick={() => {
          navigate({ to: '/posts/$postId', params: { postId: '2' } })
        }}
      >
        Navigate to Post 2
      </button>
    </div>
  )
}

Next Steps

Congratulations! You’ve built your first TanStack Router application. Here’s what to explore next:

Core Concepts

Learn the fundamentals of routing, navigation, and data loading

File-Based Routing

Organize routes by file structure with automatic generation

Search Parameters

Master type-safe URL search parameters as application state

Error Handling

Implement robust error boundaries and fallbacks

Common Patterns

Route-Level Code Splitting

Lazy load route components for better performance:
const aboutRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/about',
}).lazy(() => import('./routes/about.lazy').then((d) => d.Route))

Search Parameter Validation

Add type-safe search params with validation:
import { z } from 'zod'
import { zodValidator } from '@tanstack/zod-adapter'

const searchRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/search',
  validateSearch: zodValidator({
    schema: z.object({
      query: z.string().optional(),
      page: z.number().default(1),
    }),
  }),
  component: function Search() {
    const { query, page } = searchRoute.useSearch()
    return <div>Searching for: {query} (page {page})</div>
  },
})

Nested Layouts

Create layouts that wrap multiple child routes:
const dashboardRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: '/dashboard',
  component: () => (
    <div className="dashboard-layout">
      <aside>Sidebar</aside>
      <main>
        <Outlet />
      </main>
    </div>
  ),
})

const dashboardIndexRoute = createRoute({
  getParentRoute: () => dashboardRoute,
  path: '/',
  component: () => <div>Dashboard Home</div>,
})
Make sure to include <Outlet /> in parent routes to render child route content.

Build docs developers (and LLMs) love