Skip to main content
rule

tanstack-query — Cursor rule: what it does, how to install

This Cursor rule guides TanStack Query v5 usage in React and TypeScript. Use it when building queries, mutations, pagination, or Suspense flows.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/tanstack-query.mdc
Open on GitHub

What tanstack-query does

The rule guides Cursor through TanStack Query v5 patterns for server state. It covers stable query keys, key factories, reusable queryOptions() definitions, mutations with cache invalidation, optimistic changes, and infinite queries.

It also includes guidance for useSuspenseQuery, prefetching, and pagination with placeholderData: keepPreviousData. The rule targets src/**/*.tsx, src/**/*.ts, and src/queries/**/*; alwaysApply is set to false.

In v5, useQuery takes an options object, so positional arguments do not fit this rule. It also keeps QueryClient at the application root rather than creating one inside a component.

What it helps with

  • organize query keys with a factory
  • define reusable queries with queryOptions()
  • invalidate cached data after a mutation
  • roll back an optimistic cache change
  • build cursor-based infinite queries

Example prompts for the agent

  • Set up the posts data layer with TanStack Query v5 and a query key factory.
  • Rewrite this useQuery call with the v5 options-object syntax and queryOptions().
  • Add an optimistic post update that restores the previous cache value when the mutation fails.

How to install tanstack-query

Manually: put the files in place

.cursor/rules/tanstack-query.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about tanstack-query

How do I install tanstack-query in Cursor?

Create the rule file at .cursor/rules/tanstack-query.mdc.

What does the tanstack-query rule do?

It gives Cursor TanStack Query v5 patterns for queries, mutations, cache updates, optimistic changes, infinite queries, and Suspense.

Which files does tanstack-query apply to?

It targets src/**/*.tsx, src/**/*.ts, and src/queries/**/*. The rule is not always active because alwaysApply is set to false.

Source text

tanstack-query.mdc · CC0-1.0
---
description: "TanStack Query v5 (React Query) patterns including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, Suspense mode, and prefetching"
globs: ["src/**/*.tsx", "src/**/*.ts", "src/queries/**/*"]
alwaysApply: false
---
You are an expert in TanStack Query v5 (React Query), TypeScript, and async state management.

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

## QueryClient Setup
```tsx
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60,
      retry: (count, error: any) => error?.status !== 404 && count < 2,
    },
  },
})
```

## Query Key Factory Pattern
```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,
}
```

## queryOptions Helper (v5)
```ts
export const postQueryOptions = (id: string) =>
  queryOptions({
    queryKey: postKeys.detail(id),
    queryFn: () => fetchPost(id),
    staleTime: 1000 * 60 * 5,
  })

// In component
const { data } = useQuery(postQueryOptions(postId))

// In router loader
loader: ({ params, context: { queryClient } }) =>
  queryClient.ensureQueryData(postQueryOptions(params.postId))
```

## Mutations
```tsx
const { mutate, isPending } = useMutation({
  mutationFn: (input: CreatePostInput) => createPost(input),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: postKeys.lists() })
  },
  onError: (error) => toast.error(error.message),
})
```

## Optimistic Updates
```tsx
const mutation = useMutation({
  mutationFn: updatePost,
  onMutate: async (updated) => {
    await queryClient.cancelQueries({ queryKey: postKeys.detail(updated.id) })
    const previous = queryClient.getQueryData(postKeys.detail(updated.id))
    queryClient.setQueryData(postKeys.detail(updated.id), updated)
    return { previous }
  },
  onError: (_, updated, ctx) => {
    queryClient.setQueryData(postKeys.detail(updated.id), ctx?.previous)
  },
  onSettled: (_, __, updated) => {
    queryClient.invalidateQueries({ queryKey: postKeys.detail(updated.id) })
  },
})
```

## Infinite Queries
```tsx
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: postKeys.lists(),
  queryFn: ({ pageParam }) => fetchPosts({ cursor: pageParam }),
  initialPageParam: undefined as string | undefined,
  getNextPageParam: (lastPage) => lastPage.nextCursor,
})
const allPosts = data?.pages.flatMap((p) => p.items) ?? []
```

## Suspense Mode (v5)
```tsx
// useSuspenseQuery — no isLoading needed, Suspense handles it
const { data } = useSuspenseQuery(postQueryOptions(postId))
// Wrap with <Suspense fallback={<Skeleton />}> + <ErrorBoundary>
```

## Key Rules
- Always define `queryOptions` outside components — never inline in `useQuery()`
- Never use `useEffect` to fetch data — use loaders or `useQuery`
- Use `placeholderData: keepPreviousData` for pagination to avoid layout shifts
- Instantiate `QueryClient` once at app root — never inside a component

© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules

Similar IDE rules

All IDE rules for Frontend and UI →

From the same set210

tensorflow-deep-learning This rule guides Cursor through TensorFlow project structure, data checks, model training, evaluation, and export. Use it when you want these practices applied to your Python files and notebooks. ★ 41,024repo stars tauri-svelte-typescript-guide-cursorrules-prompt-f A Cursor rule that sets how the agent writes desktop apps with Tauri: Svelte on the frontend, TypeScript for types. ★ 41,024repo stars tanstack-start-cursorrules-prompt-file Guides Cursor when building with TanStack Start, covering server functions, file-based routes, SSR, and streamed data. ★ 41,024repo stars tanstack-router A Cursor rule that sets agent conventions for TanStack Router v1: file-based routes, typed params and loader-based data fetching. ★ 41,024repo stars tanstack-query-v5-cursorrules-prompt-file A Cursor rule that tells the agent how to write TanStack Query v5 code: query keys, mutations, optimistic updates, Suspense and prefetching. ★ 41,024repo stars tailwind-shadcn-ui-integration-cursorrules-prompt- This Cursor rule guides Tailwind and shadcn/ui work, asking the assistant to outline a plan before writing readable TypeScript and Next.js code. ★ 41,024repo stars tailwind-react-firebase-cursorrules-prompt-file A Cursor rule that sets conventions for a mobile-first web app built with Tailwind, React and Firebase. ★ 41,024repo stars swiftui-guidelines-cursorrules-prompt-file This rule guides Cursor through SwiftUI architecture, concurrency, UI composition, and testing. Add it when you want those conventions reflected in code suggestions. ★ 41,024repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor