Safeguard
Open Source

react-query (TanStack Query): Package Health and Data-Fetching Safety

The npm react-query package froze at v3.39.3 when the project moved to @tanstack/react-query. Here is how to tell which one you are running, and how to keep server-state caching from leaking data.

Marcus Chen
DevSecOps Engineer
7 min read

The npm react-query package is frozen: version 3.39.3 is its final release, because from v4 onward the project lives at @tanstack/react-query, which is where all maintenance, bug fixes, and new development happen. If react-query still appears in your package.json, you are running a library that stopped receiving updates in 2022, and your first health check is simply confirming which package name you depend on. This guide covers the package split, what "health" looks like for each name, and the data-fetching safety questions — cache retention, retry behavior, sensitive data in query keys — that matter regardless of version.

One project, two package names

TanStack Query (formerly React Query) went through a rename that still confuses dependency audits years later:

  • react-query — versions 1.x through 3.39.3. Final release in mid-2022. No further patches of any kind, security or otherwise.
  • @tanstack/react-query — versions 4.0.0 onward. The v5 line is current and actively released; the project publishes frequently, with v5 releases numbering past 5.100.

The rename coincided with the project becoming framework-agnostic: the core moved to @tanstack/query-core, with adapters for React, Vue, Solid, Svelte, and Angular. So a modern install looks like:

npm uninstall react-query
npm install @tanstack/react-query @tanstack/react-query-devtools

From a supply chain standpoint, the important detail is that the old name was never handed over or repurposed — it simply went quiet. That is the good outcome. But it also means any vulnerability discovered in the v3 codebase in the future will not be fixed under the old name. Unmaintained-but-popular packages are exactly what dependency health checks should flag, and it is worth confirming your tooling distinguishes "no known CVEs" from "no one is looking." The react query npm listing for the old name still shows millions of weekly downloads, which tells you how much production code has not migrated.

Auditing which one you actually run

Monorepos often carry both packages transitively — one team migrated, another did not, and a shared component library pins the old name. Check explicitly:

npm ls react-query @tanstack/react-query

If both appear, you have two copies of a query cache in your bundle and, more importantly, two different security postures. Duplicate query libraries also break in subtle ways: two QueryClient instances do not share a cache, so invalidation in one is invisible to the other. Treat "old name present anywhere in the tree" as a migration ticket, not a cosmetic issue. Automated SBOM diffing makes this kind of split visible across many repos at once; it is the sort of finding a platform like Safeguard surfaces without anyone hand-running npm ls.

Migration is mechanical, mostly

Moving v3 to v4/v5 is a well-documented path with codemods for the noisy parts. The changes that bite:

  • Query keys must be arrays in v4+: useQuery(['todos', id], fn) rather than a bare string.
  • v5 unified the API to a single object signature: useQuery({ queryKey, queryFn, ...options }). Overloads were removed.
  • Renames: cacheTime became gcTime, isLoading semantics changed (the old meaning lives in isPending), and callbacks like onSuccess were removed from useQuery in v5.
  • v5 requires TypeScript 4.7+ and modern browsers.

Budget the migration by counting useQuery/useMutation call sites, run the official codemod, and fix the remainder by hand. Teams that stall usually stall on the removed onSuccess callback, which forces rethinking side effects — annoying, but the new patterns are less prone to duplicated effects on cache hits.

Data-fetching safety: the part that outlives versions

TanStack Query is a server-state cache that lives in browser memory. Most security questions about it reduce to: what is in the cache, how long does it live, and who can observe it?

Sensitive data lingers by design

Query data stays in memory for gcTime (default five minutes) after the last component unsubscribes. On logout, that means the previous user's data can survive into the next session on a shared machine unless you clear it:

async function logout() {
  await api.logout();
  queryClient.clear(); // drop all cached queries and mutations
}

If you use @tanstack/react-query-persist-client to persist the cache to localStorage or IndexedDB, the stakes rise: cached API responses now sit on disk. Persist only allowlisted queries, never tokens or PII, and version the persisted cache with a buster string so schema changes invalidate old data.

Query keys end up in more places than you think

Query keys are serialized into devtools, error messages, and any logging you attach to the cache. Putting a bearer token or email address in a key like ['user', token] leaks it into every one of those channels. Key by stable identifiers (['user', userId]) and pass secrets in the fetch function via headers.

Retries can amplify abuse

Defaults retry failed queries three times with exponential backoff. Two failure modes to design around: retrying 401/403 responses hammers your auth service for no benefit, and aggressive refetchInterval polling multiplied across tabs can look like a client-side DoS. Configure retry to bail on non-retryable status codes:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: (failureCount, error) => {
        if (error instanceof HTTPError && [401, 403, 404].includes(error.status)) return false;
        return failureCount < 3;
      },
    },
  },
});

The library does not sanitize anything

TanStack Query returns whatever your queryFn resolves. If an API response contains attacker-influenced HTML and a component renders it with dangerouslySetInnerHTML, the cache faithfully serves the payload to every subscriber — an XSS with a built-in distribution mechanism. Sanitize at render time, and treat cached data with the same suspicion as fresh network data. Client-side flaws like this are exactly what a DAST scan against your running app catches and an SCA scan does not.

Package health signals worth tracking

For @tanstack/react-query specifically, the health picture in 2025 is strong: frequent releases, a large maintainer team under the TanStack organization, extensive test coverage, and no known published vulnerabilities in the v4/v5 lines in the major advisory databases at the time of writing. Its dependency footprint is small — the React adapter plus @tanstack/query-core.

The signals to keep watching, for this or any critical dependency: release cadence suddenly stopping, maintainer account changes, and new install scripts appearing in a patch release (the query packages have none, so one appearing would be a red flag). Continuous monitoring beats annual review here — see the Safeguard Academy material on dependency health scoring if you want a rubric to apply across your stack.

FAQ

Is the npm react-query package deprecated?

Practically, yes. Version 3.39.3 is the final release under the react-query name; all development moved to @tanstack/react-query starting with v4. The old package receives no fixes of any kind.

Does react-query have known vulnerabilities?

No CVEs are published against either react-query v3 or @tanstack/react-query in the major advisory databases at the time of writing. The caveat: the v3 codebase is unmaintained, so anything found later will not be patched under the old name.

Is it safe to cache API data with TanStack Query?

Yes, if you manage lifetime deliberately: call queryClient.clear() on logout, keep secrets out of query keys, and only persist allowlisted queries if you use cache persistence. The cache is in-memory by default and holds data for gcTime after last use.

Should I upgrade from react-query v3 straight to v5?

Yes — migrate via v4's codemod first if the diff is large, but land on v5. The mechanical changes (array keys, object signature, gcTime rename) are covered by official codemods; the removed onSuccess callback usually needs manual rework.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.