feat: added TanStack Query v5 cursorrules#247
feat: added TanStack Query v5 cursorrules#247usm4nhafeez wants to merge 1 commit intoPatrickJS:mainfrom
Conversation
📝 WalkthroughWalkthroughThe changes introduce comprehensive documentation and Cursor AI ruleset for TanStack Query v5, including README updates, configuration guidelines, and pattern documentation covering QueryClient setup, query key factories, mutations, optimistic updates, infinite queries, and Suspense integration. Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~5 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new TanStack Query v5 Cursor ruleset to complement the existing React Query (older API) entry, capturing v5 patterns like queryOptions, key factories, mutations, infinite queries, and Suspense usage.
Changes:
- Added TanStack Query v5 prompt/rules content (
.cursorrules,.mdc) underrules/tanstack-query-v5-cursorrules-prompt-file/. - Added a corresponding consolidated rule file under
rules-new/. - Linked the new ruleset from the root
README.md.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc | New v5-focused guidance/examples for query keys, queryOptions, mutations, infinite queries, and Suspense. |
| rules/tanstack-query-v5-cursorrules-prompt-file/README.md | Documents what the TanStack Query v5 Cursor rules cover. |
| rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules | Adds Cursor rules text with v5 setup, patterns, and examples. |
| rules-new/tanstack-query.mdc | Adds the consolidated v5 TanStack Query rules in the rules-new format. |
| README.md | Adds an index entry pointing to the new TanStack Query v5 rules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - [React (Redux, TypeScript)](./rules/react-redux-typescript-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with Redux and TypeScript integration. | ||
| - [React (MobX)](./rules/react-mobx-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with MobX integration. | ||
| - [React (React Query)](./rules/react-query-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with React Query integration. | ||
| - [TanStack Query v5](/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. |
There was a problem hiding this comment.
The new README entry uses an absolute link (/rules/...) while surrounding entries use relative links (./rules/...). Absolute links can break when viewing the file in different contexts (e.g., GitHub vs rendered docs). Consider changing this to a relative link consistent with the rest of the list.
| - [TanStack Query v5](/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. | |
| - [TanStack Query v5](./rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. |
| export const postKeys = { | ||
| all: ['posts'] as const, | ||
| lists: () => [...postKeys.all, 'list'] as const, | ||
| list: (filters?: PostFilters) => [...postKeys.lists(), filters] as const, |
There was a problem hiding this comment.
postKeys.list appends filters even when it’s undefined, producing query keys like ['posts','list', undefined]. This makes the “no filters” key shape a bit awkward and can lead to accidental cache misses if some call sites omit the element. Consider conditionally omitting the filters segment when it’s not provided, or make filters required.
| list: (filters?: PostFilters) => [...postKeys.lists(), filters] as const, | |
| list: (filters?: PostFilters) => | |
| filters === undefined ? postKeys.lists() : [...postKeys.lists(), filters] as const, |
| defaultOptions: { | ||
| queries: { | ||
| staleTime: 1000 * 60, | ||
| retry: (count, error: any) => error?.status !== 404 && count < 2, |
There was a problem hiding this comment.
The retry callback types error as any, which conflicts with the “TypeScript best practices” goal of this ruleset and makes it easy to access non-existent properties. Prefer unknown (with narrowing) or a small structural type for the fields you use (e.g., status?: number).
| retry: (count, error: any) => error?.status !== 404 && count < 2, | |
| retry: (count, error: { status?: number }) => error.status !== 404 && count < 2, |
| export const postKeys = { | ||
| all: ['posts'] as const, | ||
| lists: () => [...postKeys.all, 'list'] as const, | ||
| list: (filters?: PostFilters) => [...postKeys.lists(), filters] as const, |
There was a problem hiding this comment.
postKeys.list appends filters even when it’s undefined, producing query keys like ['posts','list', undefined]. This makes the “no filters” key shape a bit awkward and can lead to accidental cache misses if some call sites omit the element. Consider conditionally omitting the filters segment when it’s not provided, or make filters required.
| list: (filters?: PostFilters) => [...postKeys.lists(), filters] as const, | |
| list: (filters?: PostFilters) => | |
| filters === undefined | |
| ? postKeys.lists() | |
| : [...postKeys.lists(), filters] as const, |
| defaultOptions: { | ||
| queries: { | ||
| staleTime: 1000 * 60, | ||
| retry: (count, error: any) => error?.status !== 404 && count < 2, |
There was a problem hiding this comment.
The retry callback types error as any, which conflicts with the “TypeScript best practices” goal of this ruleset and makes it easy to access non-existent properties. Prefer unknown (with narrowing) or a small structural type for the fields you use (e.g., status?: number).
| retry: (count, error: any) => error?.status !== 404 && count < 2, | |
| retry: (count, error: { status?: number }) => error.status !== 404 && count < 2, |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@README.md`:
- Line 184: Update the README link for "TanStack Query v5" so it uses a relative
path (prefix with ./) instead of an absolute path; locate the link text
"TanStack Query v5" and change the href from
"/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules" to
"./rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules" to match the
other README links.
In `@rules-new/tanstack-query.mdc`:
- Around line 1-108: Delete the duplicate file rules-new/tanstack-query.mdc
because it is identical to
rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc; remove the
file from the commit/branch (git rm rules-new/tanstack-query.mdc) and update the
PR so only the canonical file under rules/... remains, then run a quick
grep/search to confirm no other code or config references
rules-new/tanstack-query.mdc before finalizing the commit.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9acc76db-11d7-4366-a520-2620b651c933
📒 Files selected for processing (5)
README.mdrules-new/tanstack-query.mdcrules/tanstack-query-v5-cursorrules-prompt-file/.cursorrulesrules/tanstack-query-v5-cursorrules-prompt-file/README.mdrules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc
| - [React (Redux, TypeScript)](./rules/react-redux-typescript-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with Redux and TypeScript integration. | ||
| - [React (MobX)](./rules/react-mobx-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with MobX integration. | ||
| - [React (React Query)](./rules/react-query-cursorrules-prompt-file/.cursorrules) - Cursor rules for React development with React Query integration. | ||
| - [TanStack Query v5](/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. |
There was a problem hiding this comment.
Fix the link path to use relative format.
The link should start with ./ instead of / to maintain consistency with all other links in this README. As per coding guidelines, all links in the README.md file should be relative and correct.
🔗 Proposed fix
-- [TanStack Query v5](/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode.
+- [TanStack Query v5](./rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - [TanStack Query v5](/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. | |
| - [TanStack Query v5](./rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules) - Cursor rules for TanStack Query v5 including queryOptions helper, query key factories, mutations, optimistic updates, infinite queries, and Suspense mode. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` at line 184, Update the README link for "TanStack Query v5" so it
uses a relative path (prefix with ./) instead of an absolute path; locate the
link text "TanStack Query v5" and change the href from
"/rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules" to
"./rules/tanstack-query-v5-cursorrules-prompt-file/.cursorrules" to match the
other README links.
| --- | ||
| 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 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if rules-new directory is used elsewhere in the repository
fd -t d "rules-new"
# Check if there are other .mdc files and their locations
fd -e mdc
# Compare the two files to confirm they're identical
echo "=== Comparing the two tanstack-query.mdc files ==="
diff rules-new/tanstack-query.mdc rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdcRepository: PatrickJS/awesome-cursorrules
Length of output: 50385
🏁 Script executed:
#!/bin/bash
# Verify file existence and size
echo "=== File existence and sizes ==="
wc -l rules-new/tanstack-query.mdc
wc -l rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc
# Use checksum to verify if identical
echo -e "\n=== File checksums ==="
md5sum rules-new/tanstack-query.mdc
md5sum rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc
# Check for any other references to rules-new in config files
echo -e "\n=== References to rules-new in configuration files ==="
find . -maxdepth 2 -type f \( -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.md" -o -name ".cursorrules" \) -exec grep -l "rules-new" {} \; 2>/dev/null || echo "No config references found"Repository: PatrickJS/awesome-cursorrules
Length of output: 453
Remove the duplicate file rules-new/tanstack-query.mdc.
This file is identical to rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc (confirmed by matching file size and checksum) and violates the repository's standard directory structure. The rules-new/ directory doesn't follow the established rules/<feature-name>/ pattern and has no references in configuration files or documentation, suggesting it was mistakenly committed. Delete this duplicate.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@rules-new/tanstack-query.mdc` around lines 1 - 108, Delete the duplicate file
rules-new/tanstack-query.mdc because it is identical to
rules/tanstack-query-v5-cursorrules-prompt-file/tanstack-query.mdc; remove the
file from the commit/branch (git rm rules-new/tanstack-query.mdc) and update the
PR so only the canonical file under rules/... remains, then run a quick
grep/search to confirm no other code or config references
rules-new/tanstack-query.mdc before finalizing the commit.
Added TanStack Query v5 rules. The existing react-query entry covers the old API — v5 has breaking changes (queryOptions helper, new hooks, different signatures).
Summary by CodeRabbit