Grey Haven TanStack Patterns
Follow Grey Haven Studio's patterns for TanStack Start, Router, and Query in React 19 applications.
TanStack Stack Overview
Grey Haven uses the complete TanStack ecosystem:
-
TanStack Start: Full-stack React framework with server functions
-
TanStack Router: Type-safe file-based routing with loaders
-
TanStack Query: Server state management with caching
-
TanStack Table (optional): Data grids and tables
-
TanStack Form (optional): Type-safe form handling
Critical Patterns
- 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 │ └── settings/ │ └── index.tsx # /settings └── users/ ├── index.tsx # /users └── $userId.tsx # /users/:userId (dynamic param)
Key conventions:
-
__root.tsx
-
Root layout with QueryClient provider
-
_authenticated/
-
Protected route groups (underscore prefix)
-
_layout.tsx
-
Layout wrapper for route groups
-
$param.tsx
-
Dynamic route parameters
- TanStack Query Defaults
const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60000, // 1 minute default retry: 1, refetchOnWindowFocus: false, }, }, });
- Query Key Patterns
// ✅ CORRECT - Specific to general queryKey: ["user", userId] queryKey: ["users", { tenantId, page: 1 }] queryKey: ["organizations", orgId, "teams"]
// ❌ WRONG queryKey: [userId] // Missing resource type queryKey: ["getUser", userId] // Don't include function name queryKey: [{ id: userId }] // Object first is confusing
- Server Functions with Multi-Tenant
// ALWAYS include tenant_id parameter export const getUserById = createServerFn("GET", async ( userId: string, tenantId: string ) => { const user = await db.query.users.findFirst({ where: and( eq(users.id, userId), eq(users.tenant_id, tenantId) // Multi-tenant isolation! ), });
if (!user) throw new Error("User not found"); return user; });
- Route Loaders
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 <div>...</div>; }
- Mutations with Cache Invalidation
const mutation = useMutation({ mutationFn: (data: UserUpdate) => updateUser(userId, data), // Always invalidate queries after mutation onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["user", userId] }); }, });
Caching Strategy
Grey Haven uses these staleTime defaults:
Data Type staleTime Use Case
Auth data 5 minutes User sessions, tokens
User profiles 1 minute User details
Lists 1 minute Data tables, lists
Static/config 10 minutes Settings, configs
Realtime 0 (always refetch) Notifications
const STALE_TIMES = { auth: 5 * 60 * 1000, // 5 minutes user: 1 * 60 * 1000, // 1 minute list: 1 * 60 * 1000, // 1 minute static: 10 * 60 * 1000, // 10 minutes realtime: 0, // Always refetch };
Supporting Documentation
All supporting files are under 500 lines per Anthropic best practices:
examples/ - Complete code examples
-
router-patterns.md - File-based routing, layouts, navigation
-
query-patterns.md - Queries, mutations, infinite queries
-
server-functions.md - Creating and using server functions
-
advanced-patterns.md - Dependent queries, parallel queries, custom hooks
-
INDEX.md - Examples navigation
reference/ - Configuration references
-
router-config.md - Router setup and configuration
-
query-config.md - QueryClient configuration
-
caching-strategy.md - Detailed caching patterns
-
multi-tenant.md - Multi-tenant patterns with RLS
-
INDEX.md - Reference navigation
templates/ - Copy-paste ready templates
-
root-route.tsx - Root layout template
-
auth-layout.tsx - Protected layout template
-
page-route.tsx - Basic page route template
-
server-function.ts - Server function template
-
custom-hook.ts - Custom query hook template
checklists/ - Pre-PR validation
- tanstack-checklist.md - TanStack patterns checklist
When to Apply This Skill
Use this skill when:
-
Building TanStack Start applications
-
Implementing routing with TanStack Router
-
Managing server state with TanStack Query
-
Creating server functions for data fetching
-
Optimizing query performance with caching
-
Implementing multi-tenant data access
-
Setting up authentication flows with route protection
-
Building data-heavy React applications
Template Reference
These patterns are from Grey Haven's production template:
- cvi-template: TanStack Start + Router + Query + React 19
Critical Reminders
-
staleTime: Default 60000ms (1 minute) for queries
-
Query keys: Specific to general (["user", userId], not [userId])
-
Server functions: Always include tenant_id parameter
-
Multi-tenant: Filter by tenant_id in all server functions
-
Loaders: Use for server-side data fetching before render
-
Mutations: Invalidate queries after successful mutation
-
Prefetching: Use for performance on hover/navigation
-
Error handling: Always handle error state in queries
-
RLS: Server functions use RLS-enabled database connection
-
File-based routing: Underscore prefix (_) for route groups/layouts