Skip to content

Performance: dehydrate() + persistence triggered on every cache update — severe blocking with large cache #9775

@wandering-sage

Description

@wandering-sage

Describe the bug

When using PersistQueryClientProvider with a large cache (≥5,000 queries), each setQueryData triggers a full dehydrate() and persistence cycle.
This causes noticeable main-thread blocking (1–3 seconds) and complete UI freeze as cache size grows.

Sandbox features:

  • Toggle to enable/disable query persistence
  • Simulates adding “work items” (each creates ~5–6 related queries)

Behavior in sandbox:

  • Persistence OFF → No lag, even with 10,000+ queries
  • Persistence ON → Adding just 100 new work items (~500 queries) causes >1 second freeze when cache already has ~5,000 queries
  • Data in sandbox is extremely lightweight — in real apps with richer data, the stall is significantly worse

Root cause

PersistQueryClientProvider subscribes to cache changes and calls persistClient() & dehydrate() on every cache mutation, including every setQueryData.
With thousands of queries, this repeatedly serializes the entire cache, blocking the main thread.

Your minimal, reproducible example

https://codesandbox.io/p/sandbox/fragrant-flower-59grjn

Steps to reproduce

Steps to reporduce:

  1. Click Add 500 work items twice.
  2. When we have 5k total queries, open the performance tab.
  3. Click Add 100 work items
  4. Observe the main thread being blocked for more than 1 second by reactQuery internals

Expected behavior

  • Persistence should be batched or throttled, not triggered on every setQueryData.
  • Alternatively, React Query could maintain an in-memory dehydrated state inside PersistQueryClientProvider and reuse it, rather than re-serializing the entire cache every time.

How often does this bug happen?

Every time

Screenshots or Videos

Live lag in the code sandbox:

Screen.Recording.2025-10-17.at.11.31.32.AM.mp4

Each long task is after adding 100 work items:
Image

Platform

  • OS: Mac OS
  • Browser: Chrome
  • Version: 140.0.7339.133

Tanstack Query adapter

None

TanStack Query version

v5+

TypeScript version

No response

Additional context

Cache Population Pattern

We're using a pattern where list mutations populate related entity caches:

queryClient.setQueryData(["works", "detail", work.id], work);
queryClient.setQueryData(["users", "detail", work.owner.id], work.owner);
queryClient.setQueryData(["teams", "detail", work.team.id], work.team);
...etc

Each of these calls triggers persistence, causing repeated dehydrations and full-cache serialization.

Observations from my app:

We saw react-query blocking the main thread for 6-7 seconds consistently on many list calls after enabling the persistent query cache.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions