React Query supports two ways of prefetching data on the server and passing that to the queryClient.
The exact implementation of these mechanisms may vary from platform to platform, but we recommend starting with Next.js which supports 2 forms of pre-rendering:
React Query supports both of these forms of pre-rendering regardless of what platform you may be using
Together with Next.js's
getServerSideProps, you can pass the data you fetch in either method to
initialData option. From React Query's perspective, these integrate in the same way,
getStaticProps is shown below:
The setup is minimal and this can be a quick solution for some cases, but there are a few tradeoffs to consider when compared to the full approach:
useQueryin a component deeper down in the tree you need to pass the
initialDatadown to that point
useQuerywith the same query in multiple locations, you need to pass
initialDatato all of them
dataUpdatedAtand determining if the query needs refetching is based on when the page loaded instead
React Query supports prefetching multiple queries on the server in Next.js and then dehydrating those queries to the queryClient. This means the server can prerender markup that is immediately available on page load and as soon as JS is available, React Query can upgrade or hydrate those queries with the full functionality of the library. This includes refetching those queries on the client if they have become stale since the time they were rendered on the server.
To support caching queries on the server and set up hydration:
QueryClientinstance inside of your app, and on an instance ref (or in React state). This ensures that data is not shared between different users and requests, while still only creating the QueryClient once per component lifecycle.
<QueryClientProvider>and pass it the client instance
<Hydrate>and pass it the
Now you are ready to prefetch some data in your pages with either
getStaticProps (for SSG) or
getServerSideProps (for SSR). From React Query's perspective, these integrate in the same way,
getStaticProps is shown below.
QueryClientinstance for each page request. This ensures that data is not shared between users and requests.
prefetchQuerymethod and wait for it to complete
dehydrateto dehydrate the query cache and pass it to the page via the
dehydratedStateprop. This is the same prop that the cache will be picked up from in your
As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content server renders or not by adding or removing
prefetchQuery for a specific query.
There's a catch if you're using Next.js' rewrites feature together with Automatic Static Optimization or
getStaticProps: It will cause a second hydration by React Query. That's because Next.js needs to ensure that they parse the rewrites on the client and collect any params after hydration so that they can be provided in
The result is missing referential equality for all the hydration data, which for example triggers whereever your data is used as props of components or in the dependency array of
This guide is at-best, a high level overview of how SSR with React Query should work. Your mileage may vary since there are many different possible setups for SSR.
If you can, please contribute your findings back to this page for any framework specific guidance!
QueryClientinstance inside of your request handler. This ensures that data is not shared between different users and requests.
SECURITY NOTE: Serializing data with
JSON.stringifycan put you at risk for XSS-vulnerabilities, this blog post explains why and how to solve it
Any query with an error is automatically excluded from dehydration. This means that the default behavior is to pretend these queries were never loaded on the server, usually showing a loading state instead, and retrying the queries on the queryClient. This happens regardless of error.
Sometimes this behavior is not desirable, maybe you want to render an error page with a correct status code instead on certain errors or queries. In those cases, use
fetchQuery and catch any errors to handle those manually.
A query is considered stale depending on when it was
dataUpdatedAt. A caveat here is that the server needs to have the correct time for this to work properly, but UTC time is used, so timezones do not factor into this.
staleTime defaults to
0, queries will be refetched in the background on page load by default. You might want to use a higher
staleTime to avoid this double fetching, especially if you don't cache your markup.
This refetching of stale queries is a perfect match when caching markup in a CDN! You can set the cache time of the page itself decently high to avoid having to re-render pages on the server, but configure the
staleTime of the queries lower to make sure data is refetched in the background as soon as a user visits the page. Maybe you want to cache the pages for a week, but refetch the data automatically on page load if it's older than a day?
In case you are creating the
QueryClient for every request, React Query creates the isolated cache for this client, which is preserved in memory for the
cacheTime period (which defaults to 5 minutes). That may lead to high memory consumption on server in case of high number of requests during that period.
To clear the cache after it is not needed and to lower memory consumption, you can add a call to
queryClient.clear() after the request is handled and dehydrated state has been sent to the client.
Alternatively, you can set a smaller