urql — Lightweight GraphQL Client
You are an expert in urql, the highly customizable and lightweight GraphQL client for React, Vue, Svelte, and vanilla JavaScript. You help developers fetch GraphQL data with minimal bundle size, document caching, normalized caching via Graphcache, exchanges (middleware pipeline), subscriptions, and offline support — providing a leaner alternative to Apollo Client with better extensibility.
Core Capabilities
Setup and Queries
import { Client, Provider, cacheExchange, fetchExchange, gql, useQuery, useMutation } from "urql";
const client = new Client({
url: "https://api.example.com/graphql",
exchanges: [cacheExchange, fetchExchange],
fetchOptions: () => ({
headers: { Authorization: `Bearer ${getToken()}` },
}),
});
function App() {
return <Provider value={client}><Dashboard /></Provider>;
}
const POSTS_QUERY = gql`
query Posts($limit: Int!) {
posts(limit: $limit) { id title author { name } createdAt }
}
`;
function PostList() {
const [result, reexecute] = useQuery({
query: POSTS_QUERY,
variables: { limit: 10 },
});
const { data, fetching, error } = result;
if (fetching) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<div>
{data.posts.map(p => <PostCard key={p.id} post={p} />)}
<button => reexecute({ requestPolicy: "network-only" })}>Refresh</button>
</div>
);
}
Mutations
const CREATE_POST = gql`
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) { id title createdAt }
}
`;
function CreatePostForm() {
const [result, createPost] = useMutation(CREATE_POST);
const handleSubmit = (data: any) => {
createPost({ input: data }).then(result => {
if (result.error) console.error(result.error);
});
};
return <Form loading={result.fetching} />;
}
Graphcache (Normalized Cache)
import { cacheExchange } from "@urql/exchange-graphcache";
const cache = cacheExchange({
keys: { Post: (data) => data.id as string },
resolvers: {
Query: {
post: (_, args) => ({ __typename: "Post", id: args.id }),
},
},
updates: {
Mutation: {
createPost(result, _args, cache) {
cache.updateQuery({ query: POSTS_QUERY, variables: { limit: 10 } }, (data) => {
if (data) data.posts.unshift(result.createPost);
return data;
});
},
},
},
});
Installation
npm install urql graphql
npm install @urql/exchange-graphcache # Optional normalized cache
Best Practices
- Document cache — Default cache deduplicates by query+variables; sufficient for most apps
- Graphcache for complex — Use normalized cache only when you need cache updates across queries
- Exchanges — urql's middleware pipeline; add auth, retry, persist, logging as composable exchanges
- Request policies — Use
cache-first (default), network-only for refresh, cache-and-network for stale-while-revalidate
- Bundle size — urql core is ~5KB gzipped (vs Apollo ~30KB); ideal for performance-sensitive apps
- SSR support — Use
ssrExchange for server-side rendering; hydrates cache on client
- Subscriptions — Add
subscriptionExchange for WebSocket/SSE subscriptions; plug and play
- Framework agnostic — Works with React, Vue, Svelte, and vanilla JS; same core, different bindings
1---2name: urql3description: You are an expert in urql, the highly customizable and lightweight GraphQL client for React, Vue, Svelte, and vanilla JavaScript. You help developers fetch GraphQL data with minimal bundle size, document caching, normalized caching via Graphcache, exchanges (middleware pipeline), subscriptions, and offline support — providing a leaner alternative to Apollo Client with better extensibility.4license: Apache-2.05---67# urql — Lightweight GraphQL Client89You are an expert in urql, the highly customizable and lightweight GraphQL client for React, Vue, Svelte, and vanilla JavaScript. You help developers fetch GraphQL data with minimal bundle size, document caching, normalized caching via Graphcache, exchanges (middleware pipeline), subscriptions, and offline support — providing a leaner alternative to Apollo Client with better extensibility.1011## Core Capabilities1213### Setup and Queries1415```tsx16import { Client, Provider, cacheExchange, fetchExchange, gql, useQuery, useMutation } from "urql";1718const client = new Client({19 url: "https://api.example.com/graphql",20 exchanges: [cacheExchange, fetchExchange],21 fetchOptions: () => ({22 headers: { Authorization: `Bearer ${getToken()}` },23 }),24});2526function App() {27 return <Provider value={client}><Dashboard /></Provider>;28}2930const POSTS_QUERY = gql`31 query Posts($limit: Int!) {32 posts(limit: $limit) { id title author { name } createdAt }33 }34`;3536function PostList() {37 const [result, reexecute] = useQuery({38 query: POSTS_QUERY,39 variables: { limit: 10 },40 });4142 const { data, fetching, error } = result;43 if (fetching) return <Spinner />;44 if (error) return <Error message={error.message} />;45 return (46 <div>47 {data.posts.map(p => <PostCard key={p.id} post={p} />)}48 <button onClick={() => reexecute({ requestPolicy: "network-only" })}>Refresh</button>49 </div>50 );51}52```5354### Mutations5556```tsx57const CREATE_POST = gql`58 mutation CreatePost($input: CreatePostInput!) {59 createPost(input: $input) { id title createdAt }60 }61`;6263function CreatePostForm() {64 const [result, createPost] = useMutation(CREATE_POST);6566 const handleSubmit = (data: any) => {67 createPost({ input: data }).then(result => {68 if (result.error) console.error(result.error);69 });70 };7172 return <Form onSubmit={handleSubmit} loading={result.fetching} />;73}74```7576### Graphcache (Normalized Cache)7778```typescript79import { cacheExchange } from "@urql/exchange-graphcache";8081const cache = cacheExchange({82 keys: { Post: (data) => data.id as string },83 resolvers: {84 Query: {85 post: (_, args) => ({ __typename: "Post", id: args.id }),86 },87 },88 updates: {89 Mutation: {90 createPost(result, _args, cache) {91 cache.updateQuery({ query: POSTS_QUERY, variables: { limit: 10 } }, (data) => {92 if (data) data.posts.unshift(result.createPost);93 return data;94 });95 },96 },97 },98});99```100101## Installation102103```bash104npm install urql graphql105npm install @urql/exchange-graphcache # Optional normalized cache106```107108## Best Practices1091101. **Document cache** — Default cache deduplicates by query+variables; sufficient for most apps1112. **Graphcache for complex** — Use normalized cache only when you need cache updates across queries1123. **Exchanges** — urql's middleware pipeline; add auth, retry, persist, logging as composable exchanges1134. **Request policies** — Use `cache-first` (default), `network-only` for refresh, `cache-and-network` for stale-while-revalidate1145. **Bundle size** — urql core is ~5KB gzipped (vs Apollo ~30KB); ideal for performance-sensitive apps1156. **SSR support** — Use `ssrExchange` for server-side rendering; hydrates cache on client1167. **Subscriptions** — Add `subscriptionExchange` for WebSocket/SSE subscriptions; plug and play1178. **Framework agnostic** — Works with React, Vue, Svelte, and vanilla JS; same core, different bindings