Skip to main content

How does RTK Query cache data?

1. What RTK Query does overall

RTK Query is a layer on top of Redux Toolkit that:

  • makes network requests (fetch/axios, etc.);
  • caches responses;
  • updates the UI from the cache without repeated requests;
  • automatically refetches data when needed.

The idea:

React components don't know about requests directly - they just subscribe to "data", and RTK Query itself decides whether to take it from the cache or from the server.


2. How the cache is structured internally

RTK Query stores cached data in the Redux store inside its own "slice", created via createApi().

javascript
const api = createApi({ reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: builder => ({ getUser: builder.query<User, string>({ query: (id) => `/user/${id}`, }), }), });

After calling:

javascript
const { data } = useGetUserQuery('42');

the Redux store gets a structure roughly like this:

javascript
state.api = { queries: { 'getUser("42")': { status: 'fulfilled', data: { id: 42, name: 'Tim' }, fulfilledTimeStamp: 1718256635100, }, }, mutations: {}, provided: { users: { '42': ['getUser("42")'] } }, }

That is, RTK Query stores:

  • the query key (endpointName + arguments);
  • the resulting data (data);
  • the cache time;
  • references to components subscribed to that data.

3. Key concept: Query Cache Key

Each query forms a unique cache key, based on:

  • the endpoint name (getUser),
  • the arguments ('42').

Example:

javascript
const cacheKey = 'getUser("42")'

React components calling useGetUserQuery('42') subscribe to the same key. If data for that key already exists, RTK Query takes it from the cache instead of fetching again.


4. When RTK Query uses the cache vs. makes a new request

ScenarioWhat RTK Query does
Another component calls useGetUserQuery('42')Uses the cache (a single source of truth)
Fewer than keepUnusedDataFor seconds have passed since the last component unmountedStill keeps the data in the cache
More than keepUnusedDataFor seconds have passedRemoves the cache
refetch() is calledMakes a new request, updates the cache
An "invalidation" happens via a tagRemoves the cache and makes a new request

5. keepUnusedDataFor: cache lifetime

By default, RTK Query keeps data in the cache for 60 seconds after the last subscribed component unmounts.

javascript
builder.query({ query: () => '/posts', keepUnusedDataFor: 120, // keep data for 2 minutes });

If another component requests /posts again within those 120 seconds, RTK Query takes the data from the cache, without a network request.


6. Tag-based cache and automatic invalidation

RTK Query supports tags to manage the cache at the entity level (users, posts, etc.).

Example:

javascript
const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api' }), tagTypes: ['User'], endpoints: builder => ({ getUser: builder.query<User, number>({ query: id => `/user/${id}`, providesTags: (result, error, id) => [{ type: 'User', id }], }), updateUser: builder.mutation<void, User>({ query: user => ({ url: `/user/${user.id}`, method: 'PUT', body: user, }), invalidatesTags: (result, error, user) => [{ type: 'User', id: user.id }], }), }), });

What happens:

  1. getUser(42) caches data under the tag {type: 'User', id: 42}.
  2. When updateUser({id: 42, ...}) is called, RTK Query invalidates the tag.
  3. All cached queries that provide that tag (providesTags) become invalid.
  4. RTK Query automatically refetches the data.

7. Behavior with multiple components

javascript
function Profile() { const { data } = useGetUserQuery('42'); return <div>{data?.name}</div>; } function Sidebar() { const { data } = useGetUserQuery('42'); return <div>{data?.name}</div>; }

Both components use the same cache key, so there's just one request to the server.

  • The first component triggers the fetch.
  • The second gets the data from the cache immediately, without a request.
  • If one of them unmounts, the cache still lives until keepUnusedDataFor expires.

8. How RTK Query tracks freshness

Each cached query has metadata:

  • fulfilledTimeStamp (time of the last update),
  • isFetching,
  • isSuccess,
  • isError,
  • isUninitialized.

You can manually call:

javascript
refetch(); // updates the cache

or use:

javascript
pollingInterval: 10000 // automatically update every 10 seconds

9. Cache at the Redux store level

If you look into Redux DevTools, you see something like this:

javascript
state.api.queries["getUser(42)"] = { status: "fulfilled", data: { id: 42, name: "Tim" }, fulfilledTimeStamp: 1718256635100, originalArgs: 42, requestId: "getUser-42-1", }

Each cache entry lives independently and has its own TTL (time-to-live).


10. Summary: how RTK Query caches data

MechanismWhat it does
Cache by key (endpoint + arguments)A single request per unique set of arguments
TTL via keepUnusedDataForKeeps data after unmounting
Tags (providesTags / invalidatesTags)Granular updates on mutations
refetch / pollingIntervalRefreshing stale data
Redux storeAll data is centrally cached in state
Automatic reuseComponents reuse ready cache entries

Example of a full caching cycle

  1. A component calls useGetUserQuery(42) -> RTK Query makes a request -> stores it in the store -> The component receives data

  2. A second component calls useGetUserQuery(42) -> RTK Query sees the data already exists -> Returns it immediately (0ms)

  3. The component unmounts -> RTK Query waits keepUnusedDataFor seconds

  4. If the component mounts again within that time -> data is taken from the cache, without a fetch

  5. If a mutation with invalidatesTags is called -> the corresponding cache entries are removed -> RTK Query does a refetch.


Summary

RTK Query caches data by a unique query key, stores it in the Redux store, automatically invalidates it on changes, and reuses it across components.

Cheat sheet:

  • All data lives in the Redux store, a single source of truth.
  • keepUnusedDataFor controls the cache lifetime.
  • providesTags / invalidatesTags control automatic refetching.
  • Repeated calls to useXxxQuery() with the same arguments don't refetch the data.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.