> ## 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.

# Nested Routes

# Nested Routes

Nested routes allow you to create hierarchical route structures where child routes render inside parent route layouts. This is one of the most powerful features of TanStack Router.

## Overview

Nested routes enable you to:

* Share layouts across multiple pages
* Maintain UI state across navigation
* Create complex, hierarchical navigation structures
* Load data at multiple levels of the route tree

## Basic Nested Routes

### File-Based Routing

With file-based routing, nest routes using directory structure:

```
src/routes/
  __root.tsx          → Root layout
  index.tsx           → / (home page)
  posts.tsx           → /posts (layout)
  posts/
    index.tsx         → /posts (list)
    $postId.tsx       → /posts/:postId (detail)
```

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

export const Route = createRootRoute({
  component: RootComponent,
})

function RootComponent() {
  return (
    <>
      <nav className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">Home</Link>
        <Link to="/posts" className="[&.active]:font-bold">Posts</Link>
      </nav>
      <hr />
      <Outlet /> {/* Child routes render here */}
    </>
  )
}
```

```tsx src/routes/posts.tsx theme={null}
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'
import { fetchPosts } from '../api'

export const Route = createFileRoute('/posts')({
  loader: () => fetchPosts(),
  component: PostsLayout,
})

function PostsLayout() {
  const posts = Route.useLoaderData()
  
  return (
    <div className="flex gap-4 p-4">
      <aside className="w-64">
        <h2>Posts</h2>
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              <Link
                to="/posts/$postId"
                params={{ postId: post.id }}
                className="hover:underline"
              >
                {post.title}
              </Link>
            </li>
          ))}
        </ul>
      </aside>
      <main className="flex-1">
        <Outlet /> {/* Post detail or index renders here */}
      </main>
    </div>
  )
}
```

```tsx src/routes/posts/index.tsx theme={null}
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/')({
  component: () => <div>Select a post from the sidebar</div>,
})
```

```tsx src/routes/posts/$postId.tsx theme={null}
import { createFileRoute } from '@tanstack/react-router'
import { fetchPost } from '../../api'

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ params }) => fetchPost(params.postId),
  component: PostDetail,
})

function PostDetail() {
  const post = Route.useLoaderData()
  
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  )
}
```

### Code-Based Routing

With code-based routing, use `getParentRoute` and `addChildren`:

```tsx theme={null}
import { createRootRoute, createRoute } from '@tanstack/react-router'

const rootRoute = createRootRoute({
  component: RootComponent,
})

const postsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: 'posts',
  loader: () => fetchPosts(),
  component: PostsLayout,
})

const postsIndexRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '/',
  component: () => <div>Select a post</div>,
})

const postRoute = createRoute({
  getParentRoute: () => postsRoute,
  path: '$postId',
  loader: ({ params }) => fetchPost(params.postId),
  component: PostDetail,
})

const routeTree = rootRoute.addChildren([
  postsRoute.addChildren([
    postsIndexRoute,
    postRoute,
  ]),
])
```

## Pathless Layouts

Pathless layouts wrap child routes without adding a URL segment. This is useful for shared UI like authentication layouts.

### File-Based Routing

Use `_` prefix for pathless routes:

```
src/routes/
  _auth.tsx              → Layout (no path)
  _auth/
    dashboard.tsx        → /dashboard
    settings.tsx         → /settings
```

```tsx src/routes/_auth.tsx theme={null}
import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'
import { useAuth } from '../auth'

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

function AuthLayout() {
  const auth = useAuth()
  
  return (
    <div className="min-h-screen">
      <header className="border-b p-4">
        <nav className="flex justify-between">
          <div className="flex gap-4">
            <Link to="/dashboard">Dashboard</Link>
            <Link to="/settings">Settings</Link>
          </div>
          <button onClick={() => auth.logout()}>Logout</button>
        </nav>
      </header>
      <main className="p-4">
        <Outlet />
      </main>
    </div>
  )
}
```

```tsx src/routes/_auth/dashboard.tsx theme={null}
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/_auth/dashboard')({
  component: () => <div>Dashboard Content</div>,
})
```

### Code-Based Routing

Use `id` instead of `path`:

```tsx theme={null}
const authLayoutRoute = createRoute({
  getParentRoute: () => rootRoute,
  id: '_auth',
  beforeLoad: ({ context }) => {
    if (!context.auth.isAuthenticated) {
      throw redirect({ to: '/login' })
    }
  },
  component: AuthLayout,
})

const dashboardRoute = createRoute({
  getParentRoute: () => authLayoutRoute,
  path: '/dashboard',
  component: Dashboard,
})

// Results in: /dashboard (with AuthLayout wrapper)
```

## Multi-Level Nesting

Create deeply nested route hierarchies:

```
src/routes/
  __root.tsx
  _auth.tsx
  _auth/
    settings.tsx
    settings/
      profile.tsx        → /settings/profile
      security.tsx       → /settings/security
      notifications.tsx  → /settings/notifications
```

```tsx src/routes/_auth/settings.tsx theme={null}
import { createFileRoute, Link, Outlet } from '@tanstack/react-router'

export const Route = createFileRoute('/_auth/settings')({
  component: SettingsLayout,
})

function SettingsLayout() {
  return (
    <div className="flex gap-6">
      <aside className="w-48">
        <nav className="space-y-2">
          <Link
            to="/settings/profile"
            className="block p-2 hover:bg-gray-100"
            activeProps={{ className: 'bg-blue-100' }}
          >
            Profile
          </Link>
          <Link
            to="/settings/security"
            className="block p-2 hover:bg-gray-100"
            activeProps={{ className: 'bg-blue-100' }}
          >
            Security
          </Link>
          <Link
            to="/settings/notifications"
            className="block p-2 hover:bg-gray-100"
            activeProps={{ className: 'bg-blue-100' }}
          >
            Notifications
          </Link>
        </nav>
      </aside>
      <main className="flex-1">
        <Outlet />
      </main>
    </div>
  )
}
```

## Data Loading in Nested Routes

Each level of nesting can load its own data:

```tsx src/routes/_auth.tsx theme={null}
export const Route = createFileRoute('/_auth')({
  loader: async ({ context }) => {
    // Load user data at the layout level
    const user = await fetchCurrentUser()
    return { user }
  },
  component: AuthLayout,
})
```

```tsx src/routes/_auth/dashboard.tsx theme={null}
export const Route = createFileRoute('/_auth/dashboard')({
  loader: async ({ context }) => {
    // Load dashboard-specific data
    const stats = await fetchDashboardStats()
    return { stats }
  },
  component: Dashboard,
})

function Dashboard() {
  const { stats } = Route.useLoaderData()
  const { user } = Route.useRouteContext() // From parent route
  
  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <DashboardStats stats={stats} />
    </div>
  )
}
```

## The Outlet Component

The `<Outlet />` component renders child routes. Without it, child routes won't be visible:

```tsx theme={null}
import { Outlet } from '@tanstack/react-router'

function Layout() {
  return (
    <div>
      <header>Header</header>
      <Outlet /> {/* Child routes render here */}
      <footer>Footer</footer>
    </div>
  )
}
```

## Parallel Routes

Render multiple route segments at the same level:

```tsx theme={null}
const routeTree = rootRoute.addChildren([
  indexRoute,
  aboutRoute,
  contactRoute,
  // All siblings at the same level
])
```

## Best Practices

<Note>
  **Keep layouts focused**: Each layout should handle one concern (auth, admin, public, etc.)
</Note>

<Warning>
  **Don't forget Outlet**: Every parent route that has children must render `<Outlet />` or children won't appear.
</Warning>

### Good Nesting Structure

```
__root.tsx (App shell)
├── _public.tsx (Public layout)
│   ├── index.tsx
│   ├── about.tsx
│   └── contact.tsx
└── _auth.tsx (Auth required)
    ├── dashboard.tsx
    └── settings.tsx
        ├── profile.tsx
        └── security.tsx
```

### Loading States

Show pending UI while nested data loads:

```tsx theme={null}
export const Route = createFileRoute('/posts/$postId')({
  loader: ({ params }) => fetchPost(params.postId),
  pendingComponent: () => <div>Loading post...</div>,
  component: PostDetail,
})
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Route Guards" href="./route-guards">
    Protect nested routes with authentication
  </Card>

  <Card title="Error Boundaries" href="./error-boundaries">
    Handle errors in nested route hierarchies
  </Card>
</CardGroup>
