This comparison table strives to be as accurate and as unbiased as possible. If you use any of these libraries and feel the information could be improved, feel free to suggest changes (with notes or evidence of claims) using the "Edit this page on Github" link at the bottom of this page.
|React Query||SWR (Website)||Apollo Client (Website)|
|Supported Query Syntax||Promise, REST, GraphQL||Promise, REST, GraphQL||GraphQL|
|Supported Query Keys||JSON||JSON||GraphQL Query|
|Query Key Change Detection||Deep Compare (Stable Serialization)||Referential Equality (===)||Deep Compare (Unstable Serialization)|
|Query Data Memoization Level||Query + Structural Sharing||Query||Query + Entity + Structural Sharing|
|Lagged / "Lazy" Queries1||✅||🛑||🛑|
|Outdated Query Dismissal||✅||✅||✅|
|Auto Garbage Collection||✅||🛑||🛑|
|Partial Query Matching3||✅||🛑||🛑|
|Stale While Revalidate||✅||✅||🛑|
|Stale Time Configuration||✅||🛑||🛑|
|Window Focus Refetching||✅||✅||🛑|
|Network Status Refetching||✅||✅||✅|
|React Suspense (Experimental)||✅||✅||🛑|
|Automatic Refetch after Mutation4||🔶||🔶||✅|
1 Lagged / "Lazy" Queries - React Query provides a way to continue to see an existing query's data while the next query loads (similar to the same UX that suspense will soon provide natively). This is extremely important when writing pagination UIs or infinite loading UIs where you do not want to show a hard loading state whenever a new query is requested. Other libraries do not have this capability and render a hard loading state for the new query (unless it has been prefetched), while the new query loads.
2 Render Optimization - React Query has excellent rendering performance. It will only re-render your components when a query is updated. For example because it has new data, or to indicate it is fetching. React Query also batches updates together to make sure your application only re-renders once when multiple components are using the same query. If you are only interested in the
errorproperties, you can reduce the number of renders even more by setting
3 Partial query matching - Because React Query uses deterministic query key serialization, this allows you to manipulate variable groups of queries without having to know each individual query-key that you want to match, eg. you can refetch every query that starts with
todosin its key, regardless of variables, or you can target specific queries with (or without) variables or nested properties, and even use a filter function to only match queries that pass your specific conditions.
4 Automatic Refetch after Mutation - For truly automatic refetching to happen after a mutation occurs, a schema is necessary (like the one graphQL provides) along with heuristics that help the library know how to identify individual entities and entities types in that schema.
5 Normalized Caching - React Query and SWR do not currently support automatic-normalized caching which describes storing entities in a flat architecture to avoid some high-level data duplication.