Skip to content

feat: added Next.js TanStack Query cursorrules#251

Open
usm4nhafeez wants to merge 1 commit intoPatrickJS:mainfrom
usm4nhafeez:add/nextjs-tanstack-query-cursorrules
Open

feat: added Next.js TanStack Query cursorrules#251
usm4nhafeez wants to merge 1 commit intoPatrickJS:mainfrom
usm4nhafeez:add/nextjs-tanstack-query-cursorrules

Conversation

@usm4nhafeez
Copy link
Copy Markdown

@usm4nhafeez usm4nhafeez commented Apr 13, 2026

Added rules for using TanStack Query v5 inside Next.js App Router. Covers HydrationBoundary pattern, Server Actions as mutations, and optimistic updates. No existing entry covers this combination.

Summary by CodeRabbit

  • Documentation
    • Added comprehensive guidelines for developing with Next.js App Router and TanStack Query v5. Topics include QueryClient provider configuration, server prefetch with client-side hydration patterns, mutation handling through Server Actions, cache invalidation strategies, optimistic updates with rollback, and infinite scroll patterns. Includes decision guidance for choosing between Server Components and client-side queries.

Copilot AI review requested due to automatic review settings April 13, 2026 08:25
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

This pull request introduces comprehensive documentation and cursor rules for integrating Next.js App Router with TanStack Query v5. It includes a new README entry, .cursorrules configuration file, and supporting documentation that covers architectural patterns, including the HydrationBoundary pattern, server-side prefetching with dehydration, Server Actions as mutations, and optimistic updates.

Changes

Cohort / File(s) Summary
README Entry
README.md
Added new rule entry for "Next.js (TanStack Query v5)" linking to the new cursor rules file with description of key patterns.
Cursor Rules and Documentation
rules/nextjs-tanstack-query-cursorrules-prompt-file/.cursorrules, rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc, rules/nextjs-tanstack-query-cursorrules-prompt-file/README.md
New comprehensive guidelines covering QueryProvider setup, HydrationBoundary hydration flow, queryOptions factory pattern, Server Actions as mutations, optimistic updates, infinite queries, and decision tables for Server Components vs TanStack Query.
Legacy Documentation
rules-new/nextjs-tanstack-query.mdc
Documentation file describing the Next.js App Router + TanStack Query v5 approach with client-side provider setup, server prefetch patterns, and mutation handling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • PatrickJS

Poem

🐰 A bundled bundle of docs so fine,
Query patterns aligned, a neat design,
Hydration flows and mutations true,
TanStack whispers guide us through!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding Next.js TanStack Query cursor rules. It is concise, clear, and directly reflects the primary objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
rules-new/nextjs-tanstack-query.mdc (1)

16-30: Make code examples import-complete for copy/paste reliability.

Both snippets use symbols that are never imported (useState, QueryClient, QueryClientProvider, ReactQueryDevtools, HydrationBoundary, dehydrate, useQuery). Please include imports in each example block to avoid broken generated output.

Suggested patch
 ## Provider Setup
 ```tsx
 // providers/query-provider.tsx
 'use client'
+import { useState } from 'react'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
 export function QueryProvider({ children }: { children: React.ReactNode }) {
   const [queryClient] = useState(() => new QueryClient({
     defaultOptions: { queries: { staleTime: 60 * 1000 } },
@@
 ## Server Prefetch + HydrationBoundary Pattern
 ```tsx
 // app/posts/page.tsx  (Server Component)
+import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query'
+import { postsQueryOptions } from '@/queries/posts'
+import { PostsList } from './_components/posts-list'
 export default async function PostsPage() {
@@
 // app/posts/_components/posts-list.tsx  (Client Component)
 'use client'
+import { useQuery } from '@tanstack/react-query'
+import { postsQueryOptions } from '@/queries/posts'
 export function PostsList() {

Also applies to: 34-50

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules-new/nextjs-tanstack-query.mdc` around lines 16 - 30, The examples are
missing necessary imports which break copy/paste; add imports for React's
useState and all tanstack symbols used in the snippets (useState, QueryClient,
QueryClientProvider, ReactQueryDevtools in providers/query-provider.tsx, and
HydrationBoundary, QueryClient, dehydrate in the server example, plus useQuery
in the client PostsList) so each code block is import-complete—update the top of
each example to import those exact identifiers from 'react' and
'@tanstack/react-query' / '@tanstack/react-query-devtools' as appropriate and
keep existing local imports like postsQueryOptions and PostsList unchanged.
rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc (1)

16-30: Replicate import-complete snippets here as well.

This file has the same missing-import issue in example code; please add explicit imports so generated code is immediately runnable.

Also applies to: 34-50

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc`
around lines 16 - 30, The example QueryProvider is missing explicit imports, so
add the necessary imports at the top of the file for React, useState,
QueryClient, QueryClientProvider and ReactQueryDevtools (used by the
QueryProvider function) so the snippet is runnable; update the snippet that
defines QueryProvider to include import statements for React and useState from
'react', QueryClient and QueryClientProvider from '@tanstack/react-query', and
ReactQueryDevtools from '@tanstack/react-query-devtools'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@rules-new/nextjs-tanstack-query.mdc`:
- Around line 16-30: The examples are missing necessary imports which break
copy/paste; add imports for React's useState and all tanstack symbols used in
the snippets (useState, QueryClient, QueryClientProvider, ReactQueryDevtools in
providers/query-provider.tsx, and HydrationBoundary, QueryClient, dehydrate in
the server example, plus useQuery in the client PostsList) so each code block is
import-complete—update the top of each example to import those exact identifiers
from 'react' and '@tanstack/react-query' / '@tanstack/react-query-devtools' as
appropriate and keep existing local imports like postsQueryOptions and PostsList
unchanged.

In
`@rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc`:
- Around line 16-30: The example QueryProvider is missing explicit imports, so
add the necessary imports at the top of the file for React, useState,
QueryClient, QueryClientProvider and ReactQueryDevtools (used by the
QueryProvider function) so the snippet is runnable; update the snippet that
defines QueryProvider to include import statements for React and useState from
'react', QueryClient and QueryClientProvider from '@tanstack/react-query', and
ReactQueryDevtools from '@tanstack/react-query-devtools'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 29a6543f-daac-4dd8-b1b1-1831d3593148

📥 Commits

Reviewing files that changed from the base of the PR and between fc2ce04 and d5daa2f.

📒 Files selected for processing (5)
  • README.md
  • rules-new/nextjs-tanstack-query.mdc
  • rules/nextjs-tanstack-query-cursorrules-prompt-file/.cursorrules
  • rules/nextjs-tanstack-query-cursorrules-prompt-file/README.md
  • rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Cursor ruleset for using TanStack Query v5 in a Next.js App Router codebase, focusing on server→client hydration, Server Actions as mutations, and optimistic update patterns.

Changes:

  • Introduces a new rules/nextjs-tanstack-query-cursorrules-prompt-file/ rules package with .cursorrules, an .mdc rule file, and a README.
  • Adds a corresponding rules-new/nextjs-tanstack-query.mdc entry.
  • Links the new ruleset from the repository root README.md.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rules/nextjs-tanstack-query-cursorrules-prompt-file/README.md Documents what the new ruleset covers and provides attribution.
rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc Adds an .mdc rule describing Next.js + TanStack Query v5 patterns and examples.
rules/nextjs-tanstack-query-cursorrules-prompt-file/.cursorrules Adds the main .cursorrules guidance and code examples (provider, hydration, mutations, optimistic updates, infinite queries).
rules-new/nextjs-tanstack-query.mdc Adds a rules-new version of the same .mdc rule content.
README.md Adds the new ruleset to the public list of available rules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +21
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { useState } from 'react'

export function QueryProvider({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(
() =>
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Provider snippet, children is typed as React.ReactNode but React isn’t imported. In many TS/Next.js setups this will fail with “Cannot find namespace 'React'”. Prefer import type { PropsWithChildren } from 'react' (or ReactNode) and type the props accordingly, or add an explicit React type import in the example.

Copilot uses AI. Check for mistakes.
defaultOptions: {
queries: {
staleTime: 60 * 1000,
retry: (count, error: any) => error?.status !== 404 && count < 2,
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

retry: (count, error) => error?.status !== 404 ... assumes the thrown error has an HTTP status, but the fetch examples shown (fetch(...).then(r => r.json())) won’t throw on non-2xx responses and typically won’t provide status. Either adjust the example fetchers to throw with status when !r.ok, or change the retry predicate to match the actual error type you expect.

Suggested change
retry: (count, error: any) => error?.status !== 404 && count < 2,
retry: (count) => count < 2,

Copilot uses AI. Check for mistakes.
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), (old: Post) => ({ ...old, ...updated }))
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optimistic update uses queryClient.setQueryData(..., (old: Post) => ({ ...old, ...updated })). At runtime old can be undefined (e.g., if the detail query was never fetched), and spreading undefined will throw. Update the example to safely handle undefined (return old/initialize a default) and avoid typing old as always-present.

Suggested change
queryClient.setQueryData(postKeys.detail(updated.id), (old: Post) => ({ ...old, ...updated }))
queryClient.setQueryData(postKeys.detail(updated.id), (old: Post | undefined) =>
old ? { ...old, ...updated } : old,
)

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,103 @@
---
description: Next.js App Router combined with TanStack Query v5 — HydrationBoundary pattern, Server Actions as mutations, optimistic updates, and infinite scroll
globs: ["app/**/*.tsx", "app/**/*.ts", "src/app/**/*.tsx", "src/queries/**/*"]
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frontmatter globs is formatted as a YAML array, but other .mdc rules in this repo use a single glob string (e.g. rules/nextjs-react-typescript-cursorrules-prompt-file/next-js-server-actions.mdc:3). If a tool parses these files assuming the string format, this entry may not be applied. Also consider including provider paths (e.g. src/providers/**/* / providers/**/*) since the guidance includes QueryProvider setup.

Suggested change
globs: ["app/**/*.tsx", "app/**/*.ts", "src/app/**/*.tsx", "src/queries/**/*"]
globs: "{app/**/*.tsx,app/**/*.ts,src/app/**/*.tsx,src/queries/**/*,providers/**/*,src/providers/**/*}"

Copilot uses AI. Check for mistakes.
onMutate: async (updated) => {
await queryClient.cancelQueries({ queryKey: ['posts', 'detail', updated.id] })
const previous = queryClient.getQueryData(['posts', 'detail', updated.id])
queryClient.setQueryData(['posts', 'detail', updated.id], (old: Post) => ({ ...old, ...updated }))
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same optimistic update issue as in the .cursorrules file: setQueryData(..., (old: Post) => ({ ...old, ...updated })) will throw if old is undefined. The example should defensively handle missing cached data and avoid asserting old is always a Post.

Suggested change
queryClient.setQueryData(['posts', 'detail', updated.id], (old: Post) => ({ ...old, ...updated }))
queryClient.setQueryData(
['posts', 'detail', updated.id],
(old: Post | undefined) => (old ? { ...old, ...updated } : updated),
)

Copilot uses AI. Check for mistakes.
onMutate: async (updated) => {
await queryClient.cancelQueries({ queryKey: ['posts', 'detail', updated.id] })
const previous = queryClient.getQueryData(['posts', 'detail', updated.id])
queryClient.setQueryData(['posts', 'detail', updated.id], (old: Post) => ({ ...old, ...updated }))
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optimistic update example spreads old ({ ...old, ...updated }) but old can be undefined if the cache is empty; spreading undefined throws. Update the example to guard against undefined and avoid typing old as always-present.

Suggested change
queryClient.setQueryData(['posts', 'detail', updated.id], (old: Post) => ({ ...old, ...updated }))
queryClient.setQueryData(
['posts', 'detail', updated.id],
(old: Post | undefined) => (old ? { ...old, ...updated } : updated)
)

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
globs: ["app/**/*.tsx", "app/**/*.ts", "src/app/**/*.tsx", "src/queries/**/*"]
alwaysApply: false
---

Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file appears to be a near-exact duplicate of rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc, which risks the two drifting over time—consider removing one or documenting which is the source of truth. Also, globs is expressed as a YAML array here, while most rules-new/*.mdc use a single comma-separated glob string (e.g. rules-new/react.mdc:3), so this entry may not be picked up by tooling expecting the common format.

Suggested change
globs: ["app/**/*.tsx", "app/**/*.ts", "src/app/**/*.tsx", "src/queries/**/*"]
alwaysApply: false
---
globs: "app/**/*.tsx, app/**/*.ts, src/app/**/*.tsx, src/queries/**/*"
alwaysApply: false
---
Note: This file mirrors `rules/nextjs-tanstack-query-cursorrules-prompt-file/nextjs-tanstack-query.mdc`, which should be treated as the source of truth. Keep the two files synchronized if either is updated.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants