Migrating to v3
v3 is a full rewrite of the code generator on top of a ts-morph pipeline, but the generated output is intentionally kept compatible with v2. For most projects, migrating means updating the package and regenerating — no code changes.
-
Update the package and regenerate your client:
Terminal window npm install -D @7nohe/openapi-react-query-codegen@^3npx openapi-rq -i ./petstore.yaml -
Be aware of the one change the compiler cannot catch: error responses now reject instead of silently resolving
undefineddata. If your UI already handles TanStack Query error states, nothing to do. -
If you use infinite queries (
useXxxInfinite), fix the type errors the compiler reports — see below. They are mechanical. -
Everything else is compatible — you are done.
What stays the same
Section titled “What stays the same”- All generated hooks (
useQuery,useSuspenseQuery,useMutation), prefetch andensureQueryDatafunctions, key constants, and key functions keep their v2 names and signatures. - JSDoc comments (including
@deprecated) are still emitted on every hook. - Environment requirements are mostly unchanged from v2.2.0: Node.js 22.18+,
typescript5.x or 6.x,ts-morph28.x.commander12.x through 15.x are now all accepted. @tanstack/react-query5.x is now declared as a peer dependency (#134). It was always required at runtime by the generated code; the declaration just makes your package manager enforce it.
What’s new
Section titled “What’s new”Every GET operation now also gets a queryOptions factory in queryOptions.ts, and paginatable operations get an infiniteQueryOptions factory. These are additive — existing code is unaffected.
import { useQuery } from "@tanstack/react-query";import { findPetsOptions } from "../openapi/queries";
const { data } = useQuery(findPetsOptions({ query: { limit: 10 } }));Infinite query hooks also accept initialPageParam and getNextPageParam overrides now (#156, #146), so custom pagination schemes no longer require editing the generated code:
const { data } = useFindPaginatedPetsInfinite({ query: { limit: 10 } }, undefined, { initialPageParam: "", getNextPageParam: (lastPage) => lastPage.meta?.cursor,});The infinite query family is now complete (#155):
prefetchUseXxxInfinite(queryClient, clientOptions, options?)— prefetch the first page (or more, viaoptions.pages) on the server for SSR/Next.js hydrationuseXxxSuspenseInfinite(clientOptions, queryKey?, options?)— Suspense variant sharing the same cache key asuseXxxInfinite
Prefetch and ensure functions also take TanStack Query options now (#157):
await prefetchUseFindPets(queryClient, {}, { staleTime: 5_000 });const pets = await ensureUseFindPetsData(queryClient, {}, { revalidateIfStale: true });Behavior change: error responses now reject
Section titled “Behavior change: error responses now reject”Generated query/mutation functions now call the SDK with throwOnError: true (#172). In v2, an error response silently resolved with undefined data (the hey-api runtime default is throwOnError: false), which broke ensureQueryData at runtime and never surfaced errors to TanStack Query. In v3, error responses reject, so:
isError/erroron hooks now actually fire on HTTP error responsesensureUseXxxDatarejects instead of cachingundefined- mutation
onErrorcallbacks fire as the types always claimed
If you relied on errors being swallowed, handle them via TanStack Query’s error state or try/catch around ensure* calls.
Breaking changes: infinite queries
Section titled “Breaking changes: infinite queries”In v2, an infinite query shared its cache key with the plain query for the same operation, which corrupted the cache when both were used (#140). v3 gives infinite queries their own keys and types.
1. Cache keys are hierarchical
Section titled “1. Cache keys are hierarchical”The cache key changed from ["FindPaginatedPets"] (shared with the plain query) to ["FindPaginatedPets", "infinite"]. Because the plain key stays the first segment, prefix matching now gives you granular invalidation (#174):
// Invalidate both the plain AND the infinite cache entries of the operationqueryClient.invalidateQueries({ queryKey: [useFindPaginatedPetsKey] });
// Invalidate only the infinite entries// (useFindPaginatedPetsInfiniteKey is already an array — don't wrap it)queryClient.invalidateQueries({ queryKey: useFindPaginatedPetsInfiniteKey });
// Target one exact query, params includedqueryClient.setQueryData(UseFindPaginatedPetsInfiniteKeyFn(options), updater);Note that useFindPaginatedPetsInfiniteKey is now a readonly ["FindPaginatedPets", "infinite"] tuple instead of a string. If you built keys manually from the string constant, use the exported key functions instead.
If you persist the query cache (e.g. persistQueryClient), previously cached infinite data will not match the new key and will be refetched once after the upgrade.
2. The page parameter is no longer accepted in clientOptions
Section titled “2. The page parameter is no longer accepted in clientOptions”Infinite hooks now take a dedicated options type that excludes the page parameter — TanStack Query supplies it through the pageParam mechanism. In v2 a page value passed here was silently overwritten, so removing it does not change behavior:
const { data, fetchNextPage } = useFindPaginatedPetsInfinite({ query: { page: 1, tags: [], limit: 10 }, query: { tags: [], limit: 10 },});This also fixes compilation for OpenAPI specs where the page parameter is required.
3. Specs with a required page parameter now compile
Section titled “3. Specs with a required page parameter now compile”No action needed — this was previously a compile error in the generated code. The generated XxxInfiniteClientOptions type makes the page parameter unnecessary while keeping all other parameters typed as before.