cursor / claude rules
React TanStack Router + Query Cursor Rules
Cursor rules for React SPAs combining TanStack Router v1 and TanStack Query v5. Loaders prefetch into Query, no loading spinners for route data.
## what it does
tl;dr: paste this .mdc into .cursor/rules/ and Cursor will stop suggesting loading spinners, ad-hoc fetch calls in components, or duplicate cache layers between Router and Query.
What the upstream rule covers
Sourced from PatrickJS/awesome-cursorrules → react-tanstack-router-query-cursorrules-prompt-file.mdc. The rule is the cleanest public write-up of how TanStack Router v1 loaders should prefetch into the TanStack Query v5 cache instead of fetching independently.
The architectural claim: Route-level data lives in Query. Loaders run before render and call queryClient.ensureQueryData(...). Components read from Query hooks. The result is no loading spinner on navigation — Suspense handles component-level loading only.
What it tells Cursor
- Architecture: Router owns routing, URL state, navigation; Query owns server state, caching, async data; components are pure UI reading from the Query cache; loaders bridge the two via
ensureQueryData. - Layout:
src/ routes/ # __root.tsx, index.tsx, posts/$postId.tsx queries/ # queryOptions factories (posts.ts, users.ts) api/ # fetchers (posts.ts, users.ts) lib/ # queryClient.ts, router.ts main.tsx - Query definitions: co-locate query key, fetcher, and
staleTimeinqueryOptionsfactories; share between Router loaders and component hooks; useinfiniteQueryOptionsfor paged lists. - Routing patterns: typed routes via
createRouter({ routeTree, context: { queryClient } });defaultPreload: "intent"for hover/prefetch;defaultPreloadStaleTime: 0;Registermodule augmentation so route params, search validation, and loaders are typed end-to-end. - Mutations: invalidate by prefix (
queryClient.invalidateQueries({ queryKey: postKeys.lists() })); colocateonMutate/onError/onSettledso optimistic updates roll back correctly. - Auth context: ship the current user (or auth claims) on the Router
context, fetch once at the root loader, and pass it down throughbeforeLoadguards rather than re-querying per route.
Install
mkdir -p .cursor/rules
curl -L -o .cursor/rules/react-tanstack-router-query.mdc \
https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/react-tanstack-router-query-cursorrules-prompt-file.mdc
Bootstrap the rule expects
// src/lib/queryClient.ts
import { QueryClient } from "@tanstack/react-query"
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60,
retry: (count, error: any) => error?.status !== 404 && count < 2,
},
},
})
// src/lib/router.ts
import { createRouter } from "@tanstack/react-router"
import { routeTree } from "../routeTree.gen"
import { queryClient } from "./queryClient"
export const router = createRouter({
routeTree,
context: { queryClient },
defaultPreload: "intent",
defaultPreloadStaleTime: 0,
})
declare module "@tanstack/react-router" {
interface Register {
router: typeof router
}
}
// src/main.tsx
import { RouterProvider } from "@tanstack/react-router"
import { QueryClientProvider } from "@tanstack/react-query"
import { router } from "./lib/router"
import { queryClient } from "./lib/queryClient"
ReactDOM.createRoot(document.getElementById("root")!).render(
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} context={{ queryClient }} />
</QueryClientProvider>,
)
Gotchas
- The
retry: (count, error) => error?.status !== 404 && count < 2line is load-bearing: 404s on missing entities are not retryable and shouldn’t burn the retry budget. Don’t drop the status check. defaultPreloadStaleTime: 0pairs withqueryClient’s ownstaleTime— preloaded data is revalidated on mount rather than served stale.- The upstream frontmatter is
globs: **/*, alwaysApply: false. The**/*is intentional: route files live anywhere. Do not narrow it. - Use this only if you’re on TanStack Router v1. The older
@tanstack/routerv0 package has a different loader API.
Related
- TanStack Query v5 Cursor Rules — the server-state half on its own
- React Router v7 Cursor Rules — the alternative if you don’t want TanStack’s bundle
- React Zustand Cursor Rules — client state, kept off the Query cache
- Cursor Rules Guide
## embed this badge
cache ✓ in cache.directory
