Photo by PJH on Unsplash

On this page

This chapter follows Typed operations with GraphQL Codegen.

The default cacheExchange stores operations by key. @urql/exchange-graphcache normalizes entities by __typename and id (or custom keys) so updating one mutation refreshes every query that referenced the same record.

Enable Graphcache

Replace cacheExchange with cacheExchange from @urql/exchange-graphcache:

src/urql-client.ts
import { cacheExchange } from "@urql/exchange-graphcache";
import { createClient, fetchExchange } from "urql";
export const client = createClient({
url: "/graphql",
exchanges: [cacheExchange({}), fetchExchange],
});

Pass schema (introspection JSON or codegen artifact) so Graphcache understands interfaces and unions when writing links.

Graphcache maintains:

  • Records — scalar fields keyed by entity ID (Book:1)
  • Links — relations between records (Query.books → list of Book records)

When a query returns { id, __typename, title }, later mutations can patch Book:1 and all list queries see the new title without refetching.

keys and non-ID entities

Types without a natural ID need custom keys:

cacheExchange({
keys: {
SearchResult: () => null, // embedded, not normalized
Product: (data) => data.sku as string,
},
});

Returning null from keys embeds the object under its parent instead of a standalone record.

updates after mutations

Tell Graphcache how to merge mutation results:

cacheExchange({
updates: {
Mutation: {
createBook(result, _args, cache) {
cache.updateQuery({ query: BooksDocument }, (data) => {
if (!data) return data;
return { ...data, books: [...data.books, result.createBook] };
});
},
},
},
});

Prefer cache.updateQuery and cache.writeFragment over manual cache inspection.

Optimistic updates

useMutation(CreateBookDocument, {
optimistic: {
createBook: {
id: "temp-id",
__typename: "Book",
title: "Draft",
},
},
});

Graphcache rolls back if the server errors. Match shape to the mutation selection set.

Resolvers and offline

resolvers on Graphcache can resolve fields locally when offline or while waiting for network—useful for read-through caches of computed fields. storage adapters persist the cache to IndexedDB for offline-first apps; replay queues mutations when connectivity returns.

Next: Evolving a GraphQL schema.

Check your understanding

Question 1 of 6

0 of 6 checked

  1. 1. What exchange replaces the default document cache for normalization?

Search articles

Type a word to search published articles.

Open the search page