BlogCode

Why cacheTime in React Query should always be bigger than staleTime

Written by Codemzy on September 28th, 2022

In React Query, the cacheTime and staleTime options impact how long data gets stored on the client and how often it's re-fetched from the server. Let's look at the difference between cacheTime and staleTime - and how changes to one can impact the other.

I've recently been learning React Query and feel like I am a little late to the party. But you know what they say, better late than never!

One of the early "gotchas" with React Query is how aggressively it re-fetches data. The moment your data arrives from the server, it's stale - according to React Query.

And that means it will re-fetch for fresh data whenever the user returns to the data. So you might find that users are making multiple network requests for the same data.

And you can adjust this, if you like, with staleTime.

What is staleTime?

staleTime is the length of time before your data becomes stale. The default value in React Query is staleTime: 0 - which means your data is immediately stale!

In React Query, your data can be fresh or stale.

If it's fresh, the saved (cached) data will be used repeatedly, without more API calls to the server.

If data is stale, then fresh data gets fetched anytime the window refocuses, the component re-mounts, or the network reconnects.

staleTime is 0 by default, so data is never fresh. If you have server data that changes often, that's what you want. But if your data is fairly static, you might want to extend the staleTime on your query.

E.g. If you only want to check back with the server after at least 10 minutes, you can extend the staleTime.

const { data } = useQuery(['my-data'], fetchMyData, { 
  staleTime: 10 * (60 * 1000), // 10 mins 
});

In the example above, React Query will fetch the data with useQuery and store it in the cache with the key my-data. Because we've set the staleTime the data is fresh for 10 minutes.

When data is fresh, instead of fetching the data from the server again, React Query will keep using the data in the cache.

What is cacheTime?

cacheTime is the length of time before inactive data gets removed from the cache. The default value in React Query is cacheTime: 300000 - which is 5 minutes.

In React Query, if all of the components that use a query are unmounted, then the query becomes inactive. Inactive data gets removed from the cache (deleted and garbage collected).

Even if your data is stale, rather than showing nothing, React Query can give you the cached data while it fetches fresh data from the server.

Usually, this is 5 minutes. And you probably don't need to mess around with this value very often - unless your staleTime is longer than 5 minutes.

Why should cacheTime be bigger than staleTime?

Let's go back to our earlier example, where we set staleTime to 10 minutes.

const { data } = useQuery(['my-data'], fetchMyData, { 
  staleTime: 10 * (60 * 1000), // 10 mins 
});

Say you set staleTime to 10 minutes because the data rarely changes, and you're happy for users to use data from this request for 10 minutes at least. It will save extra network requests and server resources because the data isn't likely to change within those 10 minutes.

And when it does change, it's by the user, so you can handle those changes without heading back to the server.

Happy times!

But wait, the cacheTime is still the default - 5 minutes.

If the user navigates away from the page using this query, and returns after 6 minutes, the data should still be fresh. You would be happy to use the data from the cache.

But sadly, it's gone! That lovely fresh data - which had 4 minutes of freshness left - is deleted.

That means a loading spinner (probably) and another call to the server - just to get the same data back you had before!

It doesn't make sense to throw away data if you still consider it fresh, so that's why cacheTime should always be bigger than staleTime.

const { data } = useQuery(['my-data'], fetchMyData, { 
  staleTime: 10 * (60 * 1000), // 10 mins 
  cacheTime: 15 * (60 * 1000), // 15 mins 
});

Since the default settings have cacheTime 5 minutes longer than staleTime, I tend to stick with that.

cacheTime vs staleTime

There can be some confusion between cacheTime and staleTime, and while both these options relate to the data in the cache, they control different things about your data.

For a quick recap:

  • cacheTime is the duration React Query stores inactive data before it is deleted from the cache
  • cacheTime defaults to 5 minutes
  • staleTime is the duration data is considered fresh - once it's stale any new calls to the query will trigger a re-fetch from the server
  • staleTime defaults to 0

Setting cacheTime and staleTime globally

React Query always assumes data is stale, even if it has just fetched it.

Out of the box, React Query is configured with aggressive but sane defaults. Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.

- React Query Important Defaults

For some data - data that frequently changes from multiple sources - those defaults work well. You want to keep checking with the server to get the latest updates. But if you have stable data that rarely changes, you might want to reduce network requests and avoid continuously fetching the same information.

We've seen how you can extend the staleTime to keep your data fresh for longer and reduce re-fetches per query. But you can also adjust this setting globally.

So if you want all of your data to be considered fresh for longer - you can! Instead of changing cacheTime and staleTime on useQuery, you'll set it on the QueryClient.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5*(60*1000), // 5 mins
      cacheTime: 10*(60*1000), // 10 mins
    },
  },
});

And all of your useQuery requests will have a staleTime of 5 minutes and a cacheTime of 10 minutes.

If you have any requests that need shorter settings, you can still adjust the cacheTime and staleTime options on those individual queries (useQuery) to override your new global settings.