tanstack
Auto-activate for @tanstack/ imports, useQuery, createRouter. Produces TanStack Router, Query, Table, and Form configurations for React applications. Use when: using useQuery, createRouter, React Query, TanStack Table, file-based routing, data fetching, or SPA state management. N
What it does
TanStack Ecosystem
The TanStack ecosystem provides standard libraries for modern React/TypeScript applications, emphasizing type safety, performance, and developer experience.
Quick Reference
useQuery Pattern (with Query Options Factory)
import { queryOptions, useQuery } from '@tanstack/react-query'
// Define query options as a factory -- reusable across components and loaders
export const usersQueryOptions = (filters?: UserFilters) =>
queryOptions({
queryKey: ['users', filters],
queryFn: () => api.getUsers(filters),
staleTime: 5 * 60 * 1000, // 5 minutes
})
function UsersPage() {
const { data, isLoading, error } = useQuery(usersQueryOptions())
if (isLoading) return <Spinner />
if (error) return <ErrorMessage error={error} />
return <UserList users={data} />
}
Mutations with Cache Invalidation
export function useCreateUser() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: (data: UserCreate) => api.createUser(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})
}
File-Based Routing (TanStack Router)
src/routes/
├── __root.tsx # Root layout
├── index.tsx # / route
├── _layout.tsx # Layout wrapper (no URL segment)
├── users/
│ ├── index.tsx # /users
│ ├── $userId.tsx # /users/:userId
│ └── $userId.edit.tsx # /users/:userId/edit
Route with Loader & Query Pre-fetching
import { createFileRoute } from '@tanstack/react-router'
import { queryClient } from '@/lib/query-client'
export const Route = createFileRoute('/users')({
loader: () => queryClient.ensureQueryData(usersQueryOptions()),
component: UsersPage,
})
// Route parameters
export const Route = createFileRoute('/users/$userId')({
loader: ({ params }) =>
queryClient.ensureQueryData(userQueryOptions(params.userId)),
component: UserDetailPage,
})
Search Parameters (Zod Validation)
import { z } from 'zod'
const searchSchema = z.object({
page: z.number().default(1),
sort: z.enum(['name', 'date']).default('name'),
})
export const Route = createFileRoute('/users')({
validateSearch: searchSchema,
component: UsersPage,
})
TanStack Table Basics
import { useReactTable, getCoreRowModel, flexRender, ColumnDef } from '@tanstack/react-table'
const columns: ColumnDef<User>[] = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
{
accessorKey: 'createdAt',
header: 'Joined',
cell: (info) => new Date(info.getValue<string>()).toLocaleDateString(),
},
]
function UsersTable({ users }: { users: User[] }) {
const table = useReactTable({
data: users,
columns,
getCoreRowModel: getCoreRowModel(),
})
// render with flexRender -- see references/table.md
}
<workflow>
Workflow
Step 1: Identify the Library
| Need | Library | Key Import |
|---|---|---|
| Data fetching & caching | TanStack Query | @tanstack/react-query |
| Client-side routing | TanStack Router | @tanstack/react-router |
| Table / data grid | TanStack Table | @tanstack/react-table |
| Form state & validation | TanStack Form | @tanstack/react-form |
| Lightweight state | TanStack Store | @tanstack/store |
Step 2: Implement
- Query: Define query options factories with
queryOptions()-- always setstaleTime - Router: Use file-based routing with
createFileRoute-- pre-fetch withloader - Table: Define
ColumnDef[]typed to your data -- usegetCoreRowModel()as base - Form: Use
useForm()with Zod adapter for validation
Step 3: Integrate Router + Query
- Create query options factories in a shared location (e.g.,
@/lib/queries/) - Use
ensureQueryDatain route loaders for data pre-fetching - Use the same query options in components with
useQueryfor cache hits - Prefetch on hover with
queryClient.prefetchQuery()for navigation links
Step 4: Validate
Run through the validation checkpoint below before considering the work complete.
</workflow> <guardrails>Guardrails
- Always set
staleTimeon queries -- the default (0) causes unnecessary refetches on every mount - Always use
queryKeyarrays -- include all variables the query depends on:['users', filters] - Always use
queryOptions()factory -- makes query keys reusable across components and loaders - Always handle loading and error states --
isLoading,errorfromuseQuerymust be checked - Prefetch on hover for navigation links -- use
queryClient.prefetchQuery()inonMouseEnter - Never use inline queryFn without queryKey -- keys must be stable and serializable
- Never mutate query data directly -- use
queryClient.setQueryData()for optimistic updates - TanStack Router is NOT react-router -- do not mix
<Link>components or hooks between them
Validation Checkpoint
Before delivering TanStack code, verify:
- All
useQuerycalls havestaleTimeset (viaqueryOptionsfactory or directly) - Query keys include all dependent variables (no stale closures)
- Loading and error states are handled in every component that fetches data
- Route loaders use
ensureQueryData(notfetchQuery) to leverage cache - Mutations invalidate related query keys on success
- Table column definitions are typed with
ColumnDef<T>[]
Example
Task: "Create a users list page with TanStack Router + Query, including search, pagination, and prefetch on hover."
// --- lib/queries/users.ts ---
import { queryOptions } from '@tanstack/react-query'
import { api } from '@/lib/api'
interface UserFilters {
search?: string
page?: number
}
export const usersQueryOptions = (filters: UserFilters = {}) =>
queryOptions({
queryKey: ['users', filters],
queryFn: () => api.getUsers(filters),
staleTime: 5 * 60 * 1000,
})
export const userQueryOptions = (userId: string) =>
queryOptions({
queryKey: ['users', userId],
queryFn: () => api.getUser(userId),
staleTime: 5 * 60 * 1000,
})
// --- routes/users/index.tsx ---
import { createFileRoute } from '@tanstack/react-router'
import { z } from 'zod'
import { usersQueryOptions } from '@/lib/queries/users'
import { queryClient } from '@/lib/query-client'
const searchSchema = z.object({
search: z.string().optional(),
page: z.number().default(1),
})
export const Route = createFileRoute('/users/')({
validateSearch: searchSchema,
loader: ({ search }) =>
queryClient.ensureQueryData(usersQueryOptions(search)),
component: UsersPage,
})
function UsersPage() {
const { search, page } = Route.useSearch()
const navigate = Route.useNavigate()
const { data, isLoading, error } = useQuery(
usersQueryOptions({ search, page }),
)
if (isLoading) return <Spinner />
if (error) return <ErrorMessage error={error} />
return (
<div>
<SearchInput
value={search ?? ''}
onChange={(value) => navigate({ search: { search: value, page: 1 } })}
/>
<UserList users={data.items} />
<Pagination
page={page}
totalPages={data.totalPages}
onPageChange={(p) => navigate({ search: { search, page: p } })}
/>
</div>
)
}
// --- components/UserLink.tsx ---
import { Link } from '@tanstack/react-router'
import { useQueryClient } from '@tanstack/react-query'
import { userQueryOptions } from '@/lib/queries/users'
function UserLink({ userId, name }: { userId: string; name: string }) {
const queryClient = useQueryClient()
return (
<Link
to="/users/$userId"
params={{ userId }}
onMouseEnter={() => {
queryClient.prefetchQuery(userQueryOptions(userId))
}}
>
{name}
</Link>
)
}
</example>
References Index
For detailed guides and code examples, refer to the following documents in references/:
- Router -- File-based routing, parameters, navigation, and loaders.
- Query -- Cache management, query factories, mutations, and optimistic updates.
- Table -- Headless table logic and integration.
- Form -- State management and validation adapters (Zod).
- Store -- Lightweight client-side state management.
Official References
- https://tanstack.com/router/
- https://tanstack.com/query/
- https://tanstack.com/table/
- https://tanstack.com/form/
- https://tanstack.com/store/
Shared Styleguide Baseline
- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.
- General Principles
- TanStack
- TypeScript
- Keep this skill focused on tool-specific workflows, edge cases, and integration details.
Capabilities
Install
Quality
deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (9,180 chars)