This chapter follows Schema design in GraphQL.
GraphQL is transport-shaped like any HTTP API until a client library adds caching, deduplication, and React bindings. The right choice depends on team size, need for normalized caches, and tolerance for compiler tooling.
Plain fetch and graphql-request
fetch (or axios) with a JSON body is enough for scripts and prototypes:
const res = await fetch("/graphql", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: `{ ping }` }),});graphql-request wraps the same call with typed helpers and middleware hooks. Neither caches by default nor deduplicates in-flight requests—you add that yourself or move upstack.
urql
urql (v5 on @urql/core 6) targets React, Preact, Svelte, and Vue with a small exchange pipeline: cacheExchange, fetchExchange, optional graphcacheExchange, auth, retry, and subscriptions. Defaults favor simplicity; Graphcache opt-in adds normalized storage. This series dedicates chapters to urql and codegen.
Pick urql when you want a lean client, explicit exchanges, and Guild-friendly tooling without Apollo’s ecosystem weight.
Apollo Client
Apollo Client provides InMemoryCache with field policies, @apollo/client React hooks, local state (legacy), and deep integration with Apollo Router, GraphOS, and persisted queries. The cache is powerful but requires learning typePolicies and possibleTypes for unions.
Pick Apollo when you already run GraphOS, need mature devtools, or standardize on Apollo’s platform across server and client.
Relay
Relay compiles GraphQL at build time with the Relay Compiler, colocates fragments with components, and enforces a strict data-fetching model (useLazyLoadQuery, useFragment, @appendEdge mutations). Modern Relay uses hooks instead of container HOCs.
Pick Relay for very large React codebases that benefit from compiler-enforced fragment colocation and store normalization—accepting compiler and schema compatibility constraints.
TanStack Query with GraphQL
TanStack Query treats each GraphQL operation as a query key + fetch function. You get stale-time, background refetch, and mutations without a GraphQL-specific cache. Pair with GraphQL Codegen for typed documents.
Pick TanStack Query when the team already standardized on it for REST and wants the same patterns for GraphQL without learning Apollo or urql caches.
When to choose which
| Need | Reasonable default |
|---|---|
| Script or admin tool | fetch / graphql-request |
| React app, moderate complexity | urql + codegen (this series) |
| Apollo GraphOS, enterprise graph | Apollo Client |
| Strict fragment colocation at scale | Relay |
| Shared data layer with REST | TanStack Query |
Next: Getting started with urql.
Check your understanding
Question 1 of 6
0 of 6 checked