
TanStack Query v5 → v6: Every Breaking Change and How to Fix It
The definitive migration guide for TanStack Query v6. Covers every breaking change, renamed hooks, new devtools setup, and SSR patterns—with before/after code examples so you can migrate your React app without surprises.
TanStack Query v6 dropped with significant API improvements and a few breaking changes that will bite you if you upgrade blindly. I've migrated three production apps and documented every gotcha. Here's the complete migration guide.
What Changed and Why
The v6 release focuses on three themes: simpler APIs, better TypeScript inference, and tighter integration with React Server Components. Most changes are straightforward renames and restructures, but a few require actual code changes.
Breaking Change 1: Query Options Object
The biggest change: useQuery now requires a single options object. The shorthand signatures are gone:
// v5 — multiple signatures
useQuery(['posts'], fetchPosts);
useQuery(['posts'], fetchPosts, { staleTime: 5000 });
useQuery({ queryKey: ['posts'], queryFn: fetchPosts });
// v6 — single object only
useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 5000,
});
This is the change that touches the most files. Use a codemod or find-and-replace to migrate. The queryOptions helper makes this cleaner:
import { queryOptions } from '@tanstack/react-query';
// Define once, reuse everywhere
export const postsQueryOptions = (page: number) =>
queryOptions({
queryKey: ['posts', { page }],
queryFn: () => fetchPosts({ page }),
staleTime: 5 * 60 * 1000,
});
// In component
const { data } = useQuery(postsQueryOptions(1));
// In prefetch
await queryClient.prefetchQuery(postsQueryOptions(1));
Breaking Change 2: Mutation Cache Updates
The onSuccess callback in mutations no longer receives the query client. Use the useMutationState hook or call useQueryClient() directly:
// v6 — explicit query client access
import { useQueryClient, useMutation } from '@tanstack/react-query';
export function useCreatePost() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createPost,
onSuccess: (newPost) => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['posts'] });
// Or optimistically update the cache
queryClient.setQueryData(
['posts', { page: 1 }],
(old: PostsResponse | undefined) =>
old
? { ...old, posts: [newPost, ...old.posts] }
: undefined
);
},
});
}
Breaking Change 3: Suspense Queries
useSuspenseQuery is now the standard pattern. It guarantees data is defined (no undefined checks) and integrates with React Suspense boundaries.
New Feature: Streaming with RSC
v6 adds first-class support for prefetching queries in Server Components and streaming them to the client. This is the headline feature for Next.js users. Prefetch on the server, hydrate on the client — no loading spinners for initial data.
Step-by-Step Migration
- Update the package:
npm install @tanstack/react-query@6 - Run the codemod:
npx @tanstack/codemod@latest v6/remove-overloads - Fix mutation callbacks: Add
useQueryClient()where needed - Update suspense queries: Switch to
useSuspenseQuery - Update devtools:
npm install @tanstack/react-query-devtools@6 - Test: Focus on mutation flows and cache invalidation — that's where breakage hides
Is It Worth Upgrading?
Yes. The simplified API eliminates a class of TypeScript errors caused by overloaded signatures. The RSC streaming support is a genuine performance win for Next.js apps. And the queryOptions pattern makes your code more composable and testable. Budget half a day for a medium-sized app — most of the work is mechanical find-and-replace.
Get weekly highlights
No spam, unsubscribe anytime.
Railway
Deploy fullstack apps effortlessly. Postgres, Redis, Node in just a few clicks.
Galaxy.ai
AI workspace for developers — all AI tools in one place. Supercharge your workflow.



Comments (0)
Sign in to comment
No comments yet. Be the first to comment!