4.3 KiB
TanStack Query v4 to v5 Migration Guide
Complete migration checklist for upgrading from React Query v4 to TanStack Query v5
Breaking Changes Summary
1. Object Syntax Required ⚠️
v4 allowed multiple signatures:
useQuery(['todos'], fetchTodos, { staleTime: 5000 })
useQuery(['todos'], fetchTodos)
useQuery(queryOptions)
v5 only supports object syntax:
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
staleTime: 5000
})
Migration: Use codemod or manual update
npx @tanstack/react-query-codemod v5/remove-overloads
2. Query Callbacks Removed ⚠️
Removed from queries (still work in mutations):
onSuccessonErroronSettled
v4:
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
onSuccess: (data) => console.log(data) // ❌ Removed
})
v5 - Use useEffect:
const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
useEffect(() => {
if (data) {
console.log(data)
}
}, [data])
Mutation callbacks still work:
useMutation({
mutationFn: addTodo,
onSuccess: () => {} // ✅ Still works
})
3. isLoading → isPending ⚠️
v4: isLoading meant "no data yet"
v5: isPending means "no data yet", isLoading = isPending && isFetching
// v4
const { data, isLoading } = useQuery(...)
if (isLoading) return <Loading />
// v5
const { data, isPending } = useQuery(...)
if (isPending) return <Loading />
4. cacheTime → gcTime ⚠️
// v4
cacheTime: 1000 * 60 * 60
// v5
gcTime: 1000 * 60 * 60
5. initialPageParam Required for Infinite Queries ⚠️
// v4
useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam = 0 }) => fetchProjects(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor,
})
// v5
useInfiniteQuery({
queryKey: ['projects'],
queryFn: ({ pageParam }) => fetchProjects(pageParam),
initialPageParam: 0, // ✅ Required
getNextPageParam: (lastPage) => lastPage.nextCursor,
})
6. keepPreviousData → placeholderData ⚠️
// v4
keepPreviousData: true
// v5
import { keepPreviousData } from '@tanstack/react-query'
placeholderData: keepPreviousData
7. useErrorBoundary → throwOnError ⚠️
// v4
useErrorBoundary: true
// v5
throwOnError: true
// Or conditional:
throwOnError: (error) => error.status >= 500
8. Error Type Default Changed
v4: error: unknown
v5: error: Error
If throwing non-Error types:
const { error } = useQuery<DataType, string>({
queryKey: ['data'],
queryFn: async () => {
if (fail) throw 'custom string error'
return data
},
})
Step-by-Step Migration
Step 1: Update Packages
npm install @tanstack/react-query@latest
npm install -D @tanstack/react-query-devtools@latest
Step 2: Run Codemods
# Remove function overloads
npx @tanstack/react-query-codemod v5/remove-overloads
# Replace removed/renamed methods
npx @tanstack/react-query-codemod v5/rename-properties
Step 3: Manual Fixes
- Replace query callbacks with useEffect
- Replace
isLoadingwithisPending - Replace
cacheTimewithgcTime - Add
initialPageParamto infinite queries - Replace
keepPreviousDatawithplaceholderData
Step 4: TypeScript Fixes
Update type imports:
// v4
import type { UseQueryResult } from 'react-query'
// v5
import type { UseQueryResult } from '@tanstack/react-query'
Step 5: Test Thoroughly
- Check all queries work
- Verify mutations invalidate correctly
- Test error handling
- Check infinite queries
- Verify TypeScript types
Common Migration Issues
Issue: Callbacks not firing
Cause: Query callbacks removed Fix: Use useEffect or move to mutations
Issue: isLoading always false
Cause: Meaning changed Fix: Use isPending for initial load
Issue: cacheTime not recognized
Cause: Renamed Fix: Use gcTime
Issue: infinite query type error
Cause: initialPageParam required Fix: Add initialPageParam
Full Codemod List
# All v5 codemods
npx @tanstack/react-query-codemod v5/remove-overloads
npx @tanstack/react-query-codemod v5/rename-properties
npx @tanstack/react-query-codemod v5/replace-imports
Note: Codemods may not catch everything - manual review required!