Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router

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.

Feature/Capability Key:

  • βœ… 1st-class, built-in, and ready to use with no added configuration or code
  • 🟑 Supported, but as an unofficial 3rd party or community library/contribution
  • πŸ”Ά Supported and documented, but requires extra user-code to implement
  • πŸ›‘ Not officially supported or documented.
React QuerySWR (Website)Apollo Client (Website)RTK-Query (Website)React Router (Website)
Github Repo / Stars
Platform RequirementsReactReactReact, GraphQLReduxReact
Their Comparison(none)(none)Comparison[Comparison][react-router-comparison]
Supported Query SyntaxPromise, REST, GraphQLPromise, REST, GraphQLGraphQLPromise, REST, GraphQLPromise, REST, GraphQL
Supported FrameworksReactReactReact + OthersAnyReact
Caching StrategyHierarchical Key -> ValueUnique Key -> ValueNormalized SchemaUnique Key -> ValueNested Route -> value
Cache Key StrategyJSONJSONGraphQL QueryJSONRoute Path
Cache Change DetectionDeep Compare Keys (Stable Serialization)Shallow Compare KeysDeep Compare Keys (Unstable Serialization)Key Referential Equality (===)Route Change
Data Change DetectionDeep Comparison + Structural SharingDeep Compare (via dequal)Deep Compare (Unstable Serialization)Key Referential Equality (===)Loader Run
Data MemoizationFull Structural SharingIdentity (===)Normalized IdentityIdentity (===)Identity (===)
Bundle Size +
API Definition LocationComponent, External ConfigComponentGraphQL SchemaExternal ConfigRoute Tree Configuration
Queriesβœ…βœ…βœ…βœ…βœ…
Cache Persistenceβœ…βœ…βœ…βœ…πŸ›‘ Active Routes Only 8
Devtoolsβœ…πŸŸ‘βœ…βœ…πŸ›‘
Polling/Intervalsβœ…βœ…βœ…βœ…πŸ›‘
Parallel Queriesβœ…βœ…βœ…βœ…βœ…
Dependent Queriesβœ…βœ…βœ…βœ…βœ…
Paginated Queriesβœ…βœ…βœ…βœ…βœ…
Infinite Queriesβœ…βœ…βœ…πŸ›‘πŸ›‘
Bi-directional Infinite Queriesβœ…πŸ”ΆπŸ”ΆπŸ›‘πŸ›‘
Infinite Query Refetchingβœ…βœ…πŸ›‘πŸ›‘πŸ›‘
Lagged Query Data1βœ…πŸ”ΆπŸ›‘βœ…βœ…
Selectorsβœ…πŸ›‘βœ…βœ…N/A
Initial Dataβœ…βœ…βœ…βœ…βœ…
Scroll Recoveryβœ…βœ…βœ…βœ…βœ…
Cache Manipulationβœ…βœ…βœ…βœ…πŸ›‘
Outdated Query Dismissalβœ…βœ…βœ…βœ…βœ…
Render Batching & Optimization2βœ…πŸ›‘πŸ›‘βœ…βœ…
Auto Garbage Collectionβœ…πŸ›‘πŸ›‘βœ…N/A
Mutation Hooksβœ…πŸŸ‘βœ…βœ…βœ…
Offline Mutation Supportβœ…πŸ›‘πŸŸ‘πŸ›‘πŸ›‘
Prefetching APIsβœ…πŸ”Άβœ…βœ…βœ…
Query Cancellationβœ…πŸ›‘πŸ›‘πŸ›‘βœ…
Partial Query Matching3βœ…πŸ›‘πŸ›‘βœ…N/A
Stale While Revalidateβœ…βœ…βœ…βœ…πŸ›‘
Stale Time Configurationβœ…πŸ›‘7πŸ›‘βœ…πŸ›‘
Pre-usage Query/Mutation Configuration4βœ…πŸ›‘πŸ›‘βœ…βœ…
Window Focus Refetchingβœ…βœ…πŸ›‘πŸ”ΆπŸ›‘
Network Status Refetchingβœ…βœ…βœ…πŸ”ΆπŸ›‘
General Cache Dehydration/Rehydrationβœ…πŸ›‘βœ…βœ…βœ…
Offline Cachingβœ… (Experimental)πŸ›‘βœ…πŸ”ΆπŸ›‘
React Suspense (Experimental)βœ…βœ…πŸ›‘πŸ›‘βœ…
Abstracted/Agnostic Coreβœ…πŸ›‘βœ…βœ…πŸ›‘
Automatic Refetch after Mutation5πŸ”ΆπŸ”Άβœ…βœ…βœ…
Normalized Caching6πŸ›‘πŸ›‘βœ…πŸ›‘πŸ›‘

Notes

1 Lagged Query Data - 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 data or error properties, you can reduce the number of renders even more by setting notifyOnChangeProps to ['data', 'error']. Set notifyOnChangeProps: 'tracked' to automatically track which fields are accessed and only re-render if one of them changes.

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 todos in 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 Pre-usage Query Configuration - This is simply a fancy name for being able to configure how queries and mutations will behave before they are used. For instance, a query can be fully configured with defaults beforehand and when the time comes to use it, only useQuery(key) is necessary, instead of being required to pass the fetcher and/or options with every usage. SWR does have a partial form of this feature by allowing you to pre-configure a default fetcher, but only as a global fetcher, not on a per-query basis and definitely not for mutations.

5 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.

6 Normalized Caching - React Query, SWR and RTK-Query do not currently support automatic-normalized caching which describes storing entities in a flat architecture to avoid some high-level data duplication.

7 SWR's Immutable Mode - SWR ships with an "immutable" mode that does allow you to only fetch a query once for the life of the cache, but it still does not have the concept of stale-time or conditional auto-revalidation

8 React Router cache persistence - React Router does not cache data beyond the currently matched routes. If a route is left, its data is lost.

Was this page helpful?

Resources

Subscribe to Bytes

The best JavaScript newsletter! Delivered every Monday to over 76,000 devs.

Bytes

No spam. Unsubscribe at any time.

Β© 2020 Tanner Linsley. All rights reserved.