TanStack Query v6: Complete Migration Guide from v5
Everything you need to know to migrate from TanStack Query v5 to v6 — breaking changes, new features, and a step-by-step upgrade path.
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.
Admin
Cal.com
Open source scheduling — tự host booking system, thay thế Calendly. Free & privacy-first.
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!