cursor / claude rules

TanStack Query v5 Rules

Cursor rules for TanStack Query v5. Server-state only, query key factories, queryOptions reuse, optimistic updates with rollback, infinite queries, Suspense, and prefetching.
by community updated Sep 10, 2026 other

## what it does

tl;dr: pull tanstack-query-v5-cursorrules-prompt-file.mdc from awesome-cursorrules before using TanStack Query v5 in a Cursor project. Models drift toward Redux/Zustand for server state and break the cache.

What it does

This rule set configures Cursor to use TanStack Query v5 the way it was designed: server state only, structured query keys, the queryOptions helper for shared definitions, and rollback-safe optimistic updates. Without it, models mix client state into the cache and use the v4 positional useQuery signature.

Sourced from PatrickJS/awesome-cursorrules — the community registry for .mdc Project Rules.

The rules

# TanStack Query v5 Guidelines

## Core Philosophy
- TanStack Query manages server state — it is NOT a general state manager for client-only state
- Every query should have a stable, serializable query key that uniquely describes the data
- Mutations handle writes; queries handle reads — never blur this boundary
- Prefer `queryOptions()` helper for reusable, co-located query definitions
- v5 breaking changes: `useQuery` no longer accepts positional args; always use the options object form

## Query Keys
- Always structure keys as arrays: `['entity', 'list']`, `['entity', 'detail', id]`
- Use a query key factory to avoid typos and enable easy invalidation

## queryOptions Helper (v5)
- Use `queryOptions()` to define queries once and reuse across components and loaders
- Pairs with router loaders via `queryClient.ensureQueryData(...)`

## Optimistic Updates
- Cancel in-flight queries, snapshot previous data, set new data, roll back on error, invalidate on settled

## Infinite Queries
- `getNextPageParam` returns the next cursor; `data.pages` is the array of page results

## Suspense Mode
- Use `useSuspenseQuery` (v5) paired with `<Suspense>` and `<ErrorBoundary>`
- No `isLoading` handling needed — Suspense handles it

## Performance Best Practices
- Set appropriate `staleTime` per query — defaults to `0` (always stale)
- Use `select` to subscribe to only relevant slices
- `placeholderData: keepPreviousData` for pagination
- Instantiate `QueryClient` once at app root, never inside components

## Error Handling
- `throwOnError: true` to bubble to nearest ErrorBoundary
- Conditional `retry` (e.g., skip 404)

Installation

Drop the .mdc into .cursor/rules/ of your project:

mkdir -p .cursor/rules
curl -sL \
  https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/tanstack-query-v5-cursorrules-prompt-file.mdc \
  -o .cursor/rules/tanstack-query-v5.mdc

Cursor picks up files in .cursor/rules/ automatically.

Setup snippet

// main.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60, // 1 minute default
      retry: 2,
      refetchOnWindowFocus: true,
    },
  },
})

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <YourApp />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  )
}

Query key factory

// queryKeys.ts
export const postKeys = {
  all: ['posts'] as const,
  lists: () => [...postKeys.all, 'list'] as const,
  list: (filters: PostFilters) => [...postKeys.lists(), filters] as const,
  details: () => [...postKeys.all, 'detail'] as const,
  detail: (id: string) => [...postKeys.details(), id] as const,
}

Why it helps

Without v5-aware rules, models will:

  • Pass positional args to useQuery (v4 signature — fails in v5)
  • Use Redux or Zustand for server state, duplicating the cache
  • Skip queryOptions and inline query definitions everywhere
  • Skip the cancel/snapshot/set/rollback/invalidate sequence on optimistic updates
  • Create a new QueryClient per component, breaking the cache

Gotchas

  • These are Cursor .mdc rules, not a Claude Code CLAUDE.md file.
  • v5 broke several v4 patterns. Models trained on older code default to v4.
  • useSuspenseQuery requires both a <Suspense> boundary and an <ErrorBoundary>.

## embed this badge

cache ✓ in cache.directory
![cached](https://cache.directory/badge/tanstack-query-v5.svg)