},
})
```
## Route Guards / Auth
```typescript
// src/routes/_authenticated.tsx
import { createFileRoute, redirect } from '@tanstack/react-router'
export const Route = createFileRoute('/_authenticated')({
beforeLoad: ({ context }) => {
if (!context.user) {
throw redirect({ to: '/login' })
}
},
component: Outlet,
})
// Protected routes
// src/routes/_authenticated/dashboard.tsx
// src/routes/_authenticated/profile.tsx
```
## Preloading
**Hover Preload:**
```typescript
View User
```
**Options:**
- `preload="intent"` - Preload on hover/focus
- `preload="render"` - Preload when link renders
- `preload={false}` - No preload (default)
## DevTools
```typescript
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
// Add to root layout
```
Auto-hides in production builds.
## Best Practices
1. **Use Type-Safe Navigation** - Let TypeScript catch routing errors at compile time
2. **Validate Search Params** - Use Zod schemas for search params
3. **Prefetch Data in Loaders** - Integrate with TanStack Query for optimal data fetching
4. **Use Layouts for Shared UI** - Avoid duplicating layout code across routes
5. **Lazy Load Routes** - Use `route.lazy.tsx` for code splitting
6. **Leverage Route Context** - Share data down the route tree efficiently
## Common Patterns
**Catch-All (Splat) Routes:**
**v1.x Syntax:**
```typescript
// src/routes/files/$.tsx - Catches all paths under /files/
export const Route = createFileRoute('/files/$')({
component: FileViewer,
})
function FileViewer() {
// Access splat via '_splat' key (v1.x+)
const { _splat } = Route.useParams()
// '/files/docs/readme.md' → _splat = 'docs/readme.md'
return
File: {_splat}
}
```
**v2 Migration Note:**
In TanStack Router v2 (upcoming), splat routes use `_splat` key consistently:
- v1: `params['*']` or `params._splat` (both work)
- v2: Only `params._splat` (star deprecated)
**Prepare for v2:**
```typescript
// ✅ Future-proof
const { _splat } = Route.useParams()
// ⚠️ Works in v1, deprecated in v2
const splat = Route.useParams()['*']
```
**404 Not Found Route:**
```typescript
// src/routes/$.tsx
export const Route = createFileRoute('/$')({
component: () =>
404 Not Found
,
})
```
**Optional Params:**
```typescript
// Use search params for optional data
const searchSchema = z.object({
optional: z.string().optional(),
})
```
**Multi-Level Dynamic Routes:**
```
/posts/$postId/comments/$commentId
```
## Production Best Practices (2026)
Insights from large-scale TanStack Router deployments:
### 1. File Structure = URL Structure
Colocate everything a page needs within its route folder:
```
src/routes/users/
├── $userId/
│ ├── index.tsx # Route definition
│ ├── index.lazy.tsx # Lazy component
│ ├── UserProfile.tsx # Page-specific component
│ └── useUserActions.ts # Page-specific hooks
└── index.tsx
```
Components/functions belong at the **nearest shared ancestor** in the hierarchy.
### 2. Let Router Handle Loading States
```typescript
// ✅ Recommended - Router handles loading/error
export const Route = createFileRoute('/users/$userId')({
loader: fetchUser,
pendingComponent: UserSkeleton,
errorComponent: UserError,
component: UserProfile, // Only handles happy path!
})
// ❌ Avoid - Manual loading in component
function UserProfile() {
const { data, isLoading, error } = useUser()
if (isLoading) return // Router should handle this
if (error) return // Router should handle this
return
{data.name}
}
```
### 3. Preload Strategy
```typescript
// List views → preload detail on hover
{user.name}
// Critical navigation → preload on render
Dashboard
```
### 4. Search Params for Everything Shareable
If users should be able to share or bookmark a specific view, use search params:
```typescript
const searchSchema = z.object({
tab: z.enum(['overview', 'activity', 'settings']).default('overview'),
page: z.number().default(1),
sort: z.enum(['name', 'date', 'score']).optional(),
})
```
## TanStack Start (Full-Stack Framework)
**TanStack Start** is the full-stack meta-framework built on TanStack Router:
**Stack:**
- TanStack Router (routing)
- Vite (bundler)
- Nitro (server)
- Vinxi (dev server)
**When to Consider Start:**
- New full-stack projects
- Need SSR/SSG out of the box
- Want alternatives to Next.js/Remix
- Prefer TanStack's type-safety approach
**When to Stick with Router + Vite:**
- SPAs without server requirements
- Existing Vite projects
- When you need maximum control
**Resources:**
- [TanStack Start Docs](https://tanstack.com/start)
- [Start vs Router](https://tanstack.com/start/latest/docs/framework/react/comparison)
**Note:** Start is still maturing. For production SPAs in 2026, TanStack Router + Query + Vite remains the recommended stack.
## Related Skills
- **tanstack-query** - Server state management, caching, and route loader integration
- **react-typescript** - React 19 patterns, component composition, and Actions
- **shadcn-ui** - UI components with proper route integration
- **browser-debugging** - DevTools and debugging TanStack Router
- **testing-frontend** - Testing routes and navigation