tanstack-query
TanStack Query v5 is a server state management library for React 18+ that handles data fetching, caching, synchronization, and mutations through async state management. Use it for all server state management tasks, cache invalidation, background data updates, optimistic updates, and complex data fetching workflows. This Claude Code resource covers v5 breaking changes, query key factories, TypeScript patterns, mutation strategies, authentication flows, testing with Mock Service Worker, and anti-patterns to avoid.
git clone --depth 1 https://github.com/MadAppGang/claude-code /tmp/tanstack-query && cp -r /tmp/tanstack-query/plugins/dev/skills/frontend/tanstack-query ~/.claude/skills/tanstack-querySKILL.md
# TanStack Query v5 - Complete Guide
**TanStack Query v5** (October 2023) is the async state manager for this project. It requires React 18+, features first-class Suspense support, improved TypeScript inference, and a 20% smaller bundle. This section covers production-ready patterns based on official documentation and community best practices.
### Breaking Changes in v5
**Key updates you need to know:**
1. **Single Object Signature**: All hooks now accept one configuration object:
```typescript
// ✅ v5 - single object
useQuery({ queryKey, queryFn, ...options })
// ❌ v4 - multiple overloads (deprecated)
useQuery(queryKey, queryFn, options)
```
2. **Renamed Options**:
- `cacheTime` → `gcTime` (garbage collection time)
- `keepPreviousData` → `placeholderData: keepPreviousData`
- `isLoading` now means `isPending && isFetching`
3. **Callbacks Removed from useQuery**:
- `onSuccess`, `onError`, `onSettled` removed from `useQuery`
- Use global QueryCache callbacks instead
- Prevents duplicate executions
4. **Infinite Queries Require initialPageParam**:
- No default value provided
- Must explicitly set `initialPageParam` (e.g., `0` or `null`)
5. **First-Class Suspense**:
- New dedicated hooks: `useSuspenseQuery`, `useSuspenseInfiniteQuery`
- No experimental flag needed
- Data is never undefined at type level
**Migration**: Use the official codemod for automatic migration: `npx @tanstack/query-codemods v5/replace-import-specifier`
### Smart Defaults
Query v5 ships with production-ready defaults:
```typescript
{
staleTime: 0, // Data instantly stale (refetch on mount)
gcTime: 5 * 60_000, // Keep unused cache for 5 minutes
retry: 3, // 3 retries with exponential backoff
refetchOnWindowFocus: true,// Refetch when user returns to tab
refetchOnReconnect: true, // Refetch when network reconnects
}
```
**Philosophy**: React Query is an **async state manager, not a data fetcher**. You provide the Promise; Query manages caching, background updates, and synchronization.
### Client Setup
```typescript
// src/app/providers.tsx
import { QueryClient, QueryClientProvider, QueryCache } from '@tanstack/react-query'
import { toast } from './toast' // Your notification system
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 0, // Adjust per-query
gcTime: 5 * 60_000, // 5 minutes (v5: formerly cacheTime)
retry: (failureCount, error) => {
// Don't retry on 401 (authentication errors)
if (error?.response?.status === 401) return false
return failureCount < 3
},
},
},
queryCache: new QueryCache({
onError: (error, query) => {
// Only show toast for background errors (when data exists)
if (query.state.data !== undefined) {
toast.error(`Something went wrong: ${error.message}`)
}
},
}),
})
export function AppProviders({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
)
}
```
**DevTools Setup** (auto-excluded in production):
```typescript
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
```
### Server-Side Rendering Configuration
When using TanStack Query with SSR (Next.js, Remix, TanStack Start), configure server-specific defaults:
```typescript
// Server-side QueryClient configuration
export function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
// Server: Don't retry on server (fail fast)
retry: typeof window === 'undefined' ? 0 : 3,
// Server: Data is always fresh when rendered
staleTime: 60_000, // 1 minute
},
},
})
}
```
**Server vs Client Defaults:**
| Option | Client Default | Server Recommended | Why |
|--------|---------------|-------------------|-----|
| `retry` | 3 | 0 | Server should fail fast, not retry loops |
| `staleTime` | 0 | 60_000+ | Server-rendered data is fresh |
| `gcTime` | 5 min | Infinity | No garbage collection needed on server |
| `refetchOnWindowFocus` | true | false | No window on server |
| `refetchOnReconnect` | true | false | No reconnect on server |
**Important:** In SPA-only apps (TanStack Router + Vite), you don't need these server defaults. They're only relevant for SSR frameworks.
### Streaming SSR (Experimental)
For Next.js App Router, `@tanstack/react-query-next-experimental` enables streaming:
```bash
pnpm add @tanstack/react-query-next-experimental
```
**Setup:**
```typescript
// app/providers.tsx
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: { staleTime: 60_000 },
},
})
}
let browserQueryClient: QueryClient | undefined
function getQueryClient() {
if (typeof window === 'undefined') {
return makeQueryClient() // Server: always new
}
return (browserQueryClient ??= makeQueryClient()) // Browser: singleton
}
export function Providers({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient()
return (
<QueryClientProvider client={queryClient}>
<ReactQueryStreamedHydration>{children}</ReactQueryStreamedHydration>
</QueryClientProvider>
)
}
```
**Usage in Client Components:**
```typescript
'use client'
import { useSuspenseQuery } from '@tanstack/react-query'
export function UserProfile({ userId }: { userId: string }) {
// No prefetch needed! Data streams from server
const { data: user } = useSuspenseQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
})
return <div>{user.name}</div>|
|
|
Common agent patterns and templates for Claude Code. Use when implementing agents to follow proven patterns for Tasks integration, quality checks, and external model invocation via claudish CLI.
YAML frontmatter schemas for Claude Code agents and commands. Use when creating or validating agent/command files.
XML tag structure patterns for Claude Code agents and commands. Use when designing or implementing agents to ensure proper XML structure following Anthropic best practices.
YAML format for Claude Code agent definitions as alternative to markdown. Use when creating agents with YAML, converting markdown agents to YAML, or validating YAML agent schemas. Trigger keywords - "YAML agent", "agent YAML", "YAML format", "agent schema", "YAML definition", "convert to YAML".
Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.