SkillAgentSearch skills...

nextjs-tanstack-query-cursorrules-prompt-file

Cursor rules for Next.js App Router with TanStack Query v5, covering the HydrationBoundary pattern, Server Actions as mutations, and optimistic updates.

Install / Use

npx skills add PatrickJS/awesome-cursorrules

Installs into whichever agent you are using.

About this skill
📦

Other

Other agent config

Quality Score

94/100

Category

Marketing

Supported Platforms

Cursor

Our assessment of nextjs-tanstack-query-cursorrules-prompt-file

nextjs-tanstack-query-cursorrules-prompt-file scores 94/100 on our quality scale, 75th of 582 Marketing skills we index (top 13%).

Its Other is 7.5 KB long, well organised into 11 sections with 7 code examples: a thorough specification that gives an agent plenty to work with.

With 41,113 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
29/30
Structure
20/20
Description
15/15
Adoption
20/20
Freshness
11/15

Maintenance, license and trust

  • The repository was last updated about 5 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
  • Our last check on 2026-10-17 found the source still online.
  • It is released under the CC0-1.0 license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 98/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.

AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.

nextjs-tanstack-query-cursorrules-prompt-file compared with similar skills

All 4 of these similar skills score higher than nextjs-tanstack-query-cursorrules-prompt-file; compare them before choosing.

SkillScoreStarsUpdatedFormat
nextjs-tanstack-query-cursorrules-prompt-file (this skill)by PatrickJS9441.1k5mo agoOther
Agent-Reachby Panniantong100109.3ktodayCLAUDE.md
headroomby headroomlabs-ai10079.0ktodayCLAUDE.md
Scraplingby D4Vinci10098.3ktodayMCP Server
crawl4aiby unclecode10087.0k1d agoMCP Server

Frequently asked questions

How do I install nextjs-tanstack-query-cursorrules-prompt-file?
Run npx skills add PatrickJS/awesome-cursorrules. The install tabs above show the steps for each supported agent.
Which AI agents does nextjs-tanstack-query-cursorrules-prompt-file work with?
It is written for Cursor, as a Other file. Other agents that read the same format can often use it too.
Is nextjs-tanstack-query-cursorrules-prompt-file safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It is CC0-1.0-licensed and scores 98/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is nextjs-tanstack-query-cursorrules-prompt-file still maintained?
The repository was last updated about 5 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.

description: "Cursor rules for Next.js App Router with TanStack Query v5, covering the HydrationBoundary pattern, Server Actions as mutations, and optimistic updates." globs: */ alwaysApply: false

You are an expert in Next.js (App Router), TanStack Query v5, TypeScript, and combining server components with client-side data fetching.

Next.js App Router + TanStack Query v5 Guidelines

Architecture Philosophy

  • Server Components fetch data directly (no TanStack Query needed there)
  • TanStack Query lives in Client Components for interactive, real-time, or user-triggered data
  • Use React Server Components for initial page data; TanStack Query for mutations, polling, and optimistic updates
  • Hydrate the Query cache from server to avoid client waterfalls on first load

Provider Setup with Hydration

// src/providers/query-provider.tsx
'use client'
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(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            staleTime: 60 * 1000,
            retry: (count, error: any) => error?.status !== 404 && count < 2,
          },
        },
      }),
  )

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  )
}

// src/app/layout.tsx
import { QueryProvider } from '@/providers/query-provider'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <QueryProvider>{children}</QueryProvider>
      </body>
    </html>
  )
}

Hydration Pattern (Server → Client Cache)

  • Prefetch in Server Components, dehydrate state, rehydrate in client
  • This eliminates client-side loading states on first render
// src/app/posts/page.tsx (Server Component)
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
import { postsQueryOptions } from '@/queries/posts'
import { PostsList } from './_components/posts-list'

export default async function PostsPage() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery(postsQueryOptions())

  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <PostsList />
    </HydrationBoundary>
  )
}

// src/app/posts/_components/posts-list.tsx
'use client'
import { useQuery } from '@tanstack/react-query'
import { postsQueryOptions } from '@/queries/posts'

export function PostsList() {
  // Reads from pre-populated cache — no loading spinner
  const { data: posts } = useQuery(postsQueryOptions())
  return <ul>{posts?.map(p => <li key={p.id}>{p.title}</li>)}</ul>
}

Query Definitions

// src/queries/posts.ts
import { queryOptions } from '@tanstack/react-query'

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,
}

export const postsQueryOptions = (filters?: PostFilters) =>
  queryOptions({
    queryKey: postKeys.list(filters),
    queryFn: () => fetch(`/api/posts`).then(r => r.json()),
  })

export const postDetailQueryOptions = (id: string) =>
  queryOptions({
    queryKey: postKeys.detail(id),
    queryFn: () => fetch(`/api/posts/${id}`).then(r => r.json()),
    staleTime: 1000 * 60 * 5,
  })

Server Actions + Mutations

  • Use Next.js Server Actions as the mutationFn in TanStack Query mutations
  • This gives you type-safe server mutations WITH optimistic update/rollback capabilities
// src/app/posts/actions.ts
'use server'
import { revalidatePath } from 'next/cache'

export async function createPost(data: { title: string; body: string }) {
  const post = await db.post.create({ data })
  revalidatePath('/posts')
  return post
}

// src/app/posts/_components/create-post-form.tsx
'use client'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { createPost } from '../actions'
import { postKeys } from '@/queries/posts'

export function CreatePostForm() {
  const queryClient = useQueryClient()
  const mutation = useMutation({
    mutationFn: createPost,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: postKeys.lists() })
    },
  })

  return (
    <button
      onClick={() => mutation.mutate({ title: 'New Post', body: '...' })}
      disabled={mutation.isPending}
    >
      {mutation.isPending ? 'Creating...' : 'Create Post'}
    </button>
  )
}

Optimistic Updates with Server Actions

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), (old: Post) => ({ ...old, ...updated }))
    return { previous }
  },
  onError: (_, updated, ctx) => {
    queryClient.setQueryData(postKeys.detail(updated.id), ctx?.previous)
  },
  onSettled: (_, __, updated) => {
    queryClient.invalidateQueries({ queryKey: postKeys.detail(updated.id) })
  },
})

When to Use Server Components vs TanStack Query

| Use Server Components When | Use TanStack Query When | |---|---| | Static or rarely-changing data | Real-time or frequently-updated data | | SEO-critical initial content | User interactions (forms, toggles) | | No need to refetch on client | Optimistic updates needed | | Data is not shared across components | Data is shared across many components | | No loading states desired | Fine-grained loading/error UI needed |

Route Handlers (API Routes) as Query Targets

  • Use src/app/api/ route handlers as the API layer for TanStack Query fetchers
  • Keep route handlers thin — just parse/validate input and call service layer
// src/app/api/posts/route.ts
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const posts = await getPosts({ category: searchParams.get('category') })
  return NextResponse.json(posts)
}

Infinite Queries (Pagination / Infinite Scroll)

'use client'
import { useInfiniteQuery } from '@tanstack/react-query'

export function InfinitePosts() {
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
    queryKey: postKeys.lists(),
    queryFn: ({ pageParam }) =>
      fetch(`/api/posts?cursor=${pageParam ?? ''}`).then(r => r.json()),
    initialPageParam: undefined as string | undefined,
    getNextPageParam: (lastPage) => lastPage.nextCursor,
  })

  const posts = data?.pages.flatMap(p => p.items) ?? []

  return (
    <div>
      {posts.map(post => <PostCard key={post.id} post={post} />)}
      <button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage}>
        {isFetchingNextPage ? 'Loading...' : 'Load More'}
      </button>
    </div>
  )
}

Key Rules

  • Create one QueryClient per request on the server side (inside Server Components)
  • Create one QueryClient per browser session on the client (via useState in provider)
  • Always use HydrationBoundary when passing server-prefetched data to client components
  • Never call fetch inside Client Components directly — always go through queryFn
  • Mark all components that use TanStack Query hooks with 'use client'

Related Skills

View on GitHub
GitHub Stars41.1k
CategoryMarketing
Updated5mo ago
Forks3.5k

Languages

JavaScript

Trust signals

98/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 info