# TanStack Router Patterns Complete examples for file-based routing, layouts, and navigation. ## File-Based Routing Structure ``` src/routes/ ├── __root.tsx # Root layout (wraps all routes) ├── index.tsx # Homepage (/) ├── _authenticated/ # Protected routes group (underscore prefix) │ ├── _layout.tsx # Auth layout wrapper │ ├── dashboard.tsx # /dashboard │ ├── profile.tsx # /profile │ └── settings/ │ ├── index.tsx # /settings │ └── billing.tsx # /settings/billing ├── auth/ │ ├── login.tsx # /auth/login │ └── signup.tsx # /auth/signup └── users/ ├── index.tsx # /users └── $userId.tsx # /users/:userId (dynamic param) ``` ## Root Layout (__root.tsx) ```typescript // src/routes/__root.tsx import { Outlet, createRootRoute } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/router-devtools"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; // Create QueryClient with Grey Haven defaults const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60000, // 1 minute default stale time retry: 1, refetchOnWindowFocus: false, }, }, }); export const Route = createRootRoute({ component: RootComponent, }); function RootComponent() { return (
{/* Child routes render here */}
); } ``` ## Route Layouts (_layout.tsx) ```typescript // src/routes/_authenticated/_layout.tsx import { Outlet, createFileRoute, redirect } from "@tanstack/react-router"; import { Header } from "~/lib/components/layout/Header"; import { Sidebar } from "~/lib/components/layout/Sidebar"; import { getSession } from "~/lib/server/functions/auth"; export const Route = createFileRoute("/_authenticated/_layout")({ // Loader runs on server for data fetching beforeLoad: async ({ context }) => { const session = await getSession(); if (!session) { throw redirect({ to: "/auth/login", search: { redirect: context.location.href, }, }); } return { session }; }, component: AuthenticatedLayout, }); function AuthenticatedLayout() { const { session } = Route.useRouteContext(); return (
{/* Child routes render here */}
); } ``` ## Page Routes with Loaders ```typescript // src/routes/_authenticated/dashboard.tsx import { createFileRoute } from "@tanstack/react-router"; import { getDashboardData } from "~/lib/server/functions/dashboard"; import { DashboardStats } from "~/lib/components/dashboard/DashboardStats"; export const Route = createFileRoute("/_authenticated/dashboard")({ // Loader fetches data on server before rendering loader: async ({ context }) => { const tenantId = context.session.tenantId; return await getDashboardData(tenantId); }, component: DashboardPage, }); function DashboardPage() { const data = Route.useLoaderData(); // Type-safe loader data return (

Dashboard

); } ``` ## Dynamic Routes ($param.tsx) ```typescript // src/routes/users/$userId.tsx import { createFileRoute } from "@tanstack/react-router"; import { getUserById } from "~/lib/server/functions/users"; import { UserProfile } from "~/lib/components/users/UserProfile"; export const Route = createFileRoute("/users/$userId")({ // Access route params in loader loader: async ({ params, context }) => { const { userId } = params; const tenantId = context.session.tenantId; return await getUserById(userId, tenantId); }, component: UserPage, }); function UserPage() { const user = Route.useLoaderData(); const { userId } = Route.useParams(); // Also available in component return (

{user.name}

); } ``` ## Navigation ```typescript import { Link, useNavigate } from "@tanstack/react-router"; function Navigation() { const navigate = useNavigate(); return ( ); } ``` ## Key Patterns ### Underscore Prefix for Groups - `_authenticated/` - Route group (doesn't add to URL) - `_layout.tsx` - Layout wrapper for group ### beforeLoad vs loader - `beforeLoad` - Auth checks, redirects - `loader` - Data fetching ### Type Safety - Route params are type-safe - Loader data is type-safe - Navigation is type-safe