Episode 26 compares alternative GraphQL clients: URQL with its exchanges system, Relay with its compiler and fragment colocation, the React Query and graphql-request combination, and a guide to choosing based on bundle size, learning curve, and application needs.

Apollo Client isn't the only option. Episode 26 covers three popular alternatives — URQL, Relay, and React Query — so you can pick the right client for each project's needs.
We'll dissect URQL's philosophy and setup with its exchanges system, Relay's compiler and fragment colocation approach, the React Query and graphql-request combination, then close with a thorough comparison.
URQL is built on the philosophy of "as small as possible, but extensible". Its bundle size is small, and almost any behavior can be modified via exchanges — structured middleware that processes every operation. Install with npm install urql graphql:
import { Client, cacheExchange, fetchExchange, Provider } from "urql";
const client = new Client({
url: "http://localhost:4000",
exchanges: [cacheExchange, fetchExchange],
});
function App() {
return <Provider value={client}>{/* komponen */}</Provider>;
}Each exchange handles one responsibility: cacheExchange for caching, fetchExchange for networking, dedupExchange for deduplication. You can arrange the order yourself, even write a custom exchange:
import { useQuery, gql } from "urql";
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) { id username }
}
`;
function Profile({ id }) {
const [result] = useQuery({ query: GET_USER, variables: { id } });
if (result.fetching) return <p>Memuat...</p>;
return <p>{result.data?.user.username}</p>;
}URQL offers two caches: the document cache (simple, good for small UIs) and the normalized cache (like Apollo, with type policies). Choose according to your data's complexity.
Relay is the most disciplined client. Every component declares its own fragment right next to the data it uses — this is called fragment colocation — then the Relay compiler turns queries into optimized artifacts:
npm install relay-runtime react-relay
npm install -D relay-compilerfragment UserCard_user on User {
id
username
avatar
}import { graphql, useFragment } from "react-relay";
function UserCard({ userRef }) {
const user = useFragment(
graphql`
fragment UserCard_user on User {
id
username
}
`,
userRef
);
return <div>{user.username}</div>;
}Relay excels at large applications with highly connected data — complex feeds, large-scale React Native — because the compiler guarantees queries are always consistent and Relay spec pagination (episode 12) is very mature. The trade-offs: a high learning curve, and server cooperation (must use the Relay spec) makes Relay less flexible for generic APIs.
The minimalist approach: use React Query for server state and graphql-request as a thin GraphQL client:
npm install @tanstack/react-query graphql-requestimport { useQuery } from "@tanstack/react-query";
import { GraphQLClient, gql } from "graphql-request";
const client = new GraphQLClient("http://localhost:4000");
function useUser(id) {
return useQuery({
queryKey: ["user", id],
queryFn: () =>
client.request(
gql`
query GetUser($id: ID!) {
user(id: $id) { id username }
}
`,
{ id }
),
});
}React Query handles caching, retries, and stale time in a transport-agnostic way — not tied to the GraphQL ecosystem. Its strengths: flexible, and easy to use with REST too. Its weaknesses: no cache normalization, so duplicated data across queries isn't synchronized automatically.
| Aspect | Apollo | URQL | Relay |
|---|---|---|---|
| Bundle size | Large | Small | Medium |
| Learning curve | Medium | Low | High |
| Normalized cache | Yes | Optional | Yes |
| Compiler | No | No | Yes (required) |
| Apollo ecosystem | Deeply integrated | Independent | Independent |
There's no absolutely wrong choice — the important thing is to match your team size, data complexity, and bundle size needs.
Key takeaways:
In the next episode, episode 27, you'll learn about integrating GraphQL with Next.js — API routes for Apollo Server, SSR with getServerSideProps and hydration, SSG with getStaticProps and ISR, App Router with Server Components, authentication with cookies, and deployment to Vercel. You'll master full-stack GraphQL with Next.js!