Direct Answer
keepUnusedDataFor is the primary and usually sufficient control for balancing RTK Query cache retention and memory. It does not need to be supplemented by manual pruning in most high-frequency update scenarios. Manual removal is only warranted when large payloads are held by long-lived subscriptions that never unmount, because the keepUnusedDataFor timer only starts after the last component unsubscribes.
What Is Actually Happening
Tag-based invalidation via providesTags and invalidatesTags marks cache entries as stale and triggers refetches, but it does not delete the existing entry from the Redux store. RTK Query intentionally prioritizes data availability: an entry remains in memory until it is overwritten by a new response, removed by a full state reset, or garbage-collected after the keepUnusedDataFor grace period expires following the last subscriber unmount.
If keepUnusedDataFor is set too high, stale entries linger and contribute to store bloat during rapid navigation. If it is set to 0, entries are purged immediately on unmount, which can cause excessive network requests and UI flickering. In RTK 2.x the default is commonly 60 seconds, which is a compromise between availability and reclamation rather than a memory-optimized setting.
Effective Strategies
- Tune
keepUnusedDataFor per slice. For high-frequency, small-to-medium datasets, lowering the value to 5–15 seconds reduces the window of unused retention without forcing immediate refetches. For rarely changing reference data, keep the default or raise it.
- Scope subscriptions tightly. Because pruning is subscription-driven, ensure
useQuery hooks mount only when data is visible. Lists rendered in background tabs or inactive routes should not hold subscriptions.
- Limit payload size at the source. RTK Query caches whatever the server returns. For large datasets, use server-side pagination, field filtering, or separate lightweight endpoints so each cache entry stays small. This is more effective than any client-side pruning policy.
- Use coarse manual resets sparingly.
api.util.resetApiState() clears the entire API cache and is useful on logout or major context switches. As of current RTK Query versions, there is no supported public action to delete a single arbitrary cache entry; api.util.invalidateTags marks entries stale but does not remove them, and api.util.updateQueryResult replaces data without freeing the entry.
When Manual Pruning Is Needed
If your application keeps components mounted for the entire session—dashboards, real-time monitors, or persistent sidebars—the keepUnusedDataFor timer never fires. In that case, memory growth is not a cache-lifetime problem but a data-volume problem. The correct fix is architectural: virtualize lists, paginate responses, or move high-volume data out of the Redux store into a dedicated state layer.
Verification
Open Redux DevTools and inspect the api.queries state. Navigate rapidly between routes that use RTK Query and watch whether entries accumulate. If entries persist after components unmount, measure how long they remain and compare that against your configured keepUnusedDataFor. Confirm that invalidatesTags triggers network requests without unexpectedly clearing unrelated entries.
One Diagnostic That Changes the Advice
Are the large datasets in your app consumed by components that unmount frequently, or do they stay mounted for the session? If they unmount, tune keepUnusedDataFor. If they stay mounted, no cache-lifetime setting will help, and you should redesign the data flow instead.