Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1--- 2title: Comparison 3order: 8 4--- 5 6# Comparison 7 8> This comparison page aims to be detailed, unbiased, and up-to-date. If you see any information that 9> may be inaccurate or could be improved otherwise, please feel free to suggest changes. 10 11The most common question that you may encounter with GraphQL is what client to choose when you are 12getting started. We aim to provide an unbiased and detailed comparison of several options on this 13page, so that you can make an **informed decision**. 14 15All options come with several drawbacks and advantages, and all of these clients have been around 16for a while now. A little known fact is that `urql` in its current form and architecture has already 17existed since February 2019, and its normalized cache has been around since September 2019. 18 19Overall, we would recommend to make your decision based on whether your required features are 20supported, which patterns you'll use (or restrictions thereof), and you may want to look into 21whether all the parts and features you're interested in are well maintained. 22 23## Comparison by Features 24 25This section is a list of commonly used features of a GraphQL client and how it's either supported 26or not by our listed alternatives. We're using Relay and Apollo to compare against as the other most 27common choices of GraphQL clients. 28 29All features are marked to indicate the following: 30 31- ✅ Supported 1st-class and documented. 32- 🔶 Supported and documented, but requires custom user-code to implement. 33- 🟡 Supported, but as an unofficial 3rd-party library. (Provided it's commonly used) 34- 🛑 Not officially supported or documented. 35 36### Core Features 37 38| | urql | Apollo | Relay | 39| ------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | 40| Extensible on a network level | ✅ Exchanges | ✅ Links | ✅ Network Layers | 41| Extensible on a cache / control flow level | ✅ Exchanges | 🛑 | 🛑 | 42| Base Bundle Size | **10kB** (11kB with bindings) | ~50kB (55kB with React hooks) | 45kB (66kB with bindings) | 43| Devtools | ✅ | ✅ | ✅ | 44| Subscriptions | 🔶 [Docs](./advanced/subscriptions.md) | 🔶 [Docs](https://www.apollographql.com/docs/react/data/subscriptions/#setting-up-the-transport) | 🔶 [Docs](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer) | 45| Client-side Rehydration | ✅ [Docs](./advanced/server-side-rendering.md) | ✅ [Docs](https://www.apollographql.com/docs/react/performance/server-side-rendering) | 🛑 | 46| Polled Queries | 🔶 | ✅ | ✅ | 47| Lazy Queries | ✅ | ✅ | ✅ | 48| Stale while Revalidate / Cache and Network | ✅ | ✅ | ✅ | 49| Focus Refetching | ✅ `@urql/exchange-refocus` | 🛑 | 🛑 | 50| Stale Time Configuration | ✅ `@urql/exchange-request-policy` | ✅ | 🛑 | 51| Persisted Queries | ✅ `@urql/exchange-persisted` | ✅ `apollo-link-persisted-queries` | 🔶 | 52| Batched Queries | 🛑 | ✅ `apollo-link-batch-http` | 🟡 `react-relay-network-layer` | 53| Live Queries | ✅ (via Incremental Delivery) | 🛑 | ✅ | 54| Defer & Stream Directives | ✅ | ✅ / 🛑 (`@defer` is supported in >=3.7.0, `@stream` is not yet supported) | 🟡 (unreleased) | 55| Switching to `GET` method | ✅ | ✅ | 🟡 `react-relay-network-layer` | 56| File Uploads | ✅ | 🟡 `apollo-upload-client` | 🛑 | 57| Retrying Failed Queries | ✅ `@urql/exchange-retry` | ✅ `apollo-link-retry` | ✅ `DefaultNetworkLayer` | 58| Easy Authentication Flows | ✅ `@urql/exchange-auth` | 🛑 (no docs for refresh-based authentication) | 🟡 `react-relay-network-layer` | 59| Automatic Refetch after Mutation | ✅ (with document cache) | 🛑 | ✅ | 60 61Typically these are all additional addon features that you may expect from a GraphQL client, no 62matter which framework you use it with. It's worth mentioning that all three clients support some 63kind of extensibility API, which allows you to change when and how queries are sent to an API. These 64are easy to use primitives particularly in Apollo, with links, and in `urql` with exchanges. The 65major difference in `urql` is that all caching logic is abstracted in exchanges too, which makes 66it easy to swap the caching logic or other behavior out (and hence makes `urql` slightly more 67customizable.) 68 69A lot of the added exchanges for persisted queries, file uploads, retrying, and other features are 70implemented by the urql-team, while there are some cases where first-party support isn't provided 71in Relay or Apollo. This doesn't mean that these features can't be used with these clients, but that 72you'd have to lean on community libraries or maintaining/implementing them yourself. 73 74One thing of note is our lack of support for batched queries in `urql`. We explicitly decided not to 75support this in our [first-party 76packages](https://github.com/urql-graphql/urql/issues/800#issuecomment-626342821) as the benefits 77are not present anymore in most cases with HTTP/2 and established patterns by Relay that recommend 78hoisting all necessary data requirements to a page-wide query. 79 80### Framework Bindings 81 82| | urql | Apollo | Relay | 83| ------------------------------ | -------------- | ------------------- | ------------------ | 84| React Bindings | ✅ | ✅ | ✅ | 85| React Concurrent Hooks Support | ✅ | ✅ | ✅ | 86| React Suspense | ✅ | 🛑 | ✅ | 87| Next.js Integration | ✅ `next-urql` | 🟡 | 🔶 | 88| Preact Support | ✅ | 🔶 | 🔶 | 89| Svelte Bindings | ✅ | 🟡 `svelte-apollo` | 🟡 `svelte-relay` | 90| Vue Bindings | ✅ | 🟡 `vue-apollo` | 🟡 `vue-relay` | 91| Angular Bindings | 🛑 | 🟡 `apollo-angular` | 🟡 `relay-angular` | 92| Initial Data on mount | ✅ | ✅ | ✅ | 93 94### Caching and State 95 96| | urql | Apollo | Relay | 97| ------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------- | ---------------------------------------------- | 98| Caching Strategy | Document Caching, Normalized Caching with `@urql/exchange-graphcache` | Normalized Caching | Normalized Caching (schema restrictions apply) | 99| Added Bundle Size | +8kB (with Graphcache) | +0 (default) | +0 (default) | 100| Automatic Garbage Collection | ✅ | 🔶 | ✅ | 101| Local State Management | 🛑 | ✅ | ✅ | 102| Pagination Support | 🔶 | 🔶 | ✅ | 103| Optimistic Updates | ✅ | ✅ | ✅ | 104| Local Updates | ✅ | ✅ | ✅ | 105| Out-of-band Cache Updates | 🛑 (stays true to server data) | ✅ | ✅ | 106| Local Resolvers and Redirects | ✅ | ✅ | 🛑 | 107| Complex Resolvers (nested non-normalized return values) | ✅ | 🛑 | 🛑 | 108| Commutativity Guarantees | ✅ | 🛑 | ✅ | 109| Partial Results | ✅ | ✅ | 🛑 | 110| Safe Partial Results (schema-based) | ✅ | 🔶 (experimental via `useFragment`) | 🛑 | 111| Persistence Support | ✅ | ✅ `apollo-cache-persist` | 🟡 `@wora/relay-store` | 112| Offline Support | ✅ | 🛑 | 🟡 `@wora/relay-offline` | 113 114`urql` is the only of the three clients that doesn't pick [normalized 115caching](./graphcache/normalized-caching.md) as its default caching strategy. Typically this is seen 116by users as easier and quicker to get started with. All entries in this table for `urql` typically 117refer to the optional `@urql/exchange-graphcache` package. 118 119Once you need the same features that you'll find in Relay and Apollo, it's possible to migrate to 120Graphcache. Graphcache is also slightly different from Apollo's cache and more opinionated as it 121doesn't allow arbitrary cache updates to be made. 122 123Local state management is not provided by choice, but could be implemented as an exchange. For more details, [see discussion here](https://github.com/urql-graphql/urql/issues/323#issuecomment-756226783). 124 125`urql` is the only library that provides [Offline Support](./graphcache/offline.md) out of the 126box as part of Graphcache's feature set. There are a number of options for Apollo and Relay including 127writing your own logic for offline caching, which can be particularly successful in Relay, but for 128`@urql/exchange-graphcache` we chose to include it as a feature since it also strengthened other 129guarantees that the cache makes. 130 131Relay does in fact have similar guarantees as [`urql`'s Commutativity 132Guarantees](./graphcache/normalized-caching/#deterministic-cache-updates), 133which are more evident when applying list updates out of order under more complex network 134conditions. 135 136## About Bundle Size 137 138`urql` is known and often cited as a "lightweight GraphQL client," which is one of its advantages 139but not its main goal. It manages to be this small by careful size management, just like other 140libraries like Preact. 141 142You may find that adding features like `@urql/exchange-persisted-fetch` and 143`@urql/exchange-graphcache` only slightly increases your bundle size as we're aiming to reduce bloat, 144but often this comparison is hard to make. When you start comparing bundle sizes of these three 145GraphQL clients you should keep in mind that: 146 147- Some dependencies may be external and the above sizes listed are total minified+gzipped sizes 148 - `@urql/core` imports from `wonka` for stream utilities and `@0no-co/graphql.web` for GraphQL query 149 language utilities 150 - Other GraphQL clients may import other exernal dependencies. 151- All `urql` packages reuse parts of `@urql/core` and `wonka`, which means adding all their total 152 sizes up doesn't give you a correct result of their total expected bundle size.