Apollo Cache: Normalization and Updates
Understand Apollo's normalized InMemoryCache and update cached data after mutations without refetching.
Apollo Cache: Normalization and Updates is a free React Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
How InMemoryCache Normalizes Data
InMemoryCache stores each object by a cache key composed of __typename and id: User:1, Post:42. When a query returns a User with id "1", it is stored once under this key regardless of how many different queries include it.
Any subsequent query that fetches the same User:1 reads from the single cache entry, ensuring all components see the same data.
Automatic Cross-Query Updates
When a mutation returns an updated User:1 object, Apollo writes it to the User:1 cache entry. Every active query that included User:1 automatically reflects the updated fields in the UI without any additional code.
This automatic propagation is the primary advantage of a normalized cache over a document (query-keyed) cache.
cache.readQuery
Read the current cached result of a query: cache.readQuery({ query: GET_USERS }) returns the data object as if useQuery had returned it. Returns null if the query is not in the cache.
Use readQuery inside mutation update functions to read the current list before modifying it.
cache.writeQuery
cache.writeQuery({ query: GET_USERS, data: { users: updatedUsers } }) writes directly to the cache, triggering re-renders in all components that read GET_USERS. No network request is made.
Combine readQuery and writeQuery to implement immutable cache updates: read, produce a new array, write back.
cache.modify for Direct Entity Updates
cache.modify({ id: cache.identify(user), fields: { name: () => 'New Name' } }) directly modifies a specific cached entity's fields. No need to read a query first when you know the entity's cache ID.
The fields object maps field names to modifier functions that receive the current value and return the new value.
Updating Cache After Mutation
Pass an update function to useMutation: useMutation(ADD_POST, { update(cache, { data: { addPost } }) { cache.modify({ id: cache.identify(user), fields: { posts: existingPosts => [...existingPosts, addPost] } }); } }).
This appends the new post to the user's cached posts array, updating all components that display the user's post list.
cache.evict: Removing Cache Entries
cache.evict({ id: 'User:1' }) removes the User:1 entry from the cache. Any active query that included User:1 will re-render with that entity missing from the result.
After evicting entries, call cache.gc() to remove any objects that are now unreachable from root queries. This prevents memory leaks in long-running applications.
Garbage Collection
cache.gc() traverses the cache graph starting from all active queries and removes any entities no longer reachable. It is safe to call periodically or after batch mutations that delete many entities.
Entities referenced by active useQuery hooks are never garbage collected, only orphaned entities that are no longer part of any query result.
Cache Redirects with Field Policies
If you query a single entity (GET_USER by id) that is already cached as part of a list query, Apollo can read it from cache without a network round-trip using field policies: keyArgs and read functions in the type policy.
The read function returns a cache reference: return toReference({ __typename: 'User', id: args.id }), telling Apollo to read from the existing User:id cache entry.
Custom keyFields for Non-Standard IDs
If your entities use a field other than id as their unique key (e.g., slug or uuid), configure it in the type policy: new InMemoryCache({ typePolicies: { Post: { keyFields: ['slug'] } } }).
Apollo then uses Post:my-post-slug as the cache key instead of requiring an id field, preserving normalization for non-standard schemas.
refetchQueries vs update Function
refetchQueries: [{ query: GET_USERS }] in useMutation options triggers a network refetch after the mutation completes. It is simpler but always makes a network request.
The update function modifies the cache locally and avoids the network round-trip. Use refetchQueries when cache update logic is too complex to write, or when server-computed fields make local cache updates unreliable.
InMemoryCache Normalization Key
What is the default cache key format used by InMemoryCache to store entities?
Lesson Recap
InMemoryCache normalizes entities by __typename+id, enabling automatic cross-query updates. Read/write the cache with cache.readQuery, cache.writeQuery, and cache.modify. Remove entities with cache.evict followed by cache.gc. Configure custom key fields via typePolicies for non-id primary keys.
Use mutation update functions for local cache efficiency; use refetchQueries when server-computed fields make local updates unreliable.
Frequently asked questions
Is the “Apollo Cache: Normalization and Updates” lesson free?
Yes — the full text of “Apollo Cache: Normalization and Updates” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.
What will I learn in “Apollo Cache: Normalization and Updates”?
Understand Apollo's normalized InMemoryCache and update cached data after mutations without refetching. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Academy?
No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Apollo Cache: Normalization and Updates” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Academy lesson?
Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- GraphQL Fundamentals for React Developers
- Setting Up Apollo Client in React
- useQuery and useMutation Hooks
- Apollo Cache: Normalization and Updates