Configure GraphQL Client Cache Policies
Set per-field cache and fetch policies so lists refresh when needed, single entities stay cache-first, and mutations update the cache without a refetch.
Task
Tune GraphQL client cache policies to stop over-fetching while keeping data fresh where it matters.
When to use this
The default cache returns stale lists after a mutation, or every navigation refetches, so the app is either wrong or slow.
Prerequisites
- A normalized GraphQL client cache
- Known freshness requirements per field
Steps
1. Use cache-first for entities that change rarely and cache-and-network for lists users expect fresh.
Expected output: Reads are fast but not stale where it matters.
2. Return the updated object from mutation responses and write it into the cache by id.
Expected output: Mutations update the UI without a refetch.
3. Invalidate or update affected list fields after mutations with an explicit update function.
Expected output: Lists stay consistent with the changed entity.
4. Set a network-only policy for highly volatile fields such as balances.
Expected output: Critical values are never served from cache.
Troubleshooting
Problem
Cache grows unbounded
Solution
Enable eviction or garbage collection and avoid caching large, rarely reused fields.
Problem
Mutation does not update lists
Solution
Use the mutation update callback to modify the cached list, since the cache cannot infer which lists include the entity.
Limitations
- Cache policy is a client concern; it cannot compensate for a server that returns inconsistent data.
- Overusing network-only defeats the cache and reintroduces the round trips you tried to remove.
Context
Tune GraphQL client cache policies to stop over-fetching while keeping data fresh where it matters. The default cache returns stale lists after a mutation, or every navigation refetches, so the app is either wrong or slow.
Steps
- Use cache-first for entities that change rarely and cache-and-network for lists users expect fresh. Expected: Reads are fast but not stale where it matters.
- Return the updated object from mutation responses and write it into the cache by id. Expected: Mutations update the UI without a refetch.
- Invalidate or update affected list fields after mutations with an explicit update function. Expected: Lists stay consistent with the changed entity.
- Set a network-only policy for highly volatile fields such as balances. Expected: Critical values are never served from cache.
useQuery(GET_USERS, { fetchPolicy: 'cache-and-network' });
useMutation(CREATE_USER, {
update(cache, { data }) {
cache.modify({ fields: { users: (prev) => [...prev, data.createUser] } });
},
});
Verify
- Reads are fast but not stale where it matters.
- Mutations update the UI without a refetch.
- Lists stay consistent with the changed entity.
- Critical values are never served from cache.
Limits
- Cache policy is a client concern; it cannot compensate for a server that returns inconsistent data.
- Overusing network-only defeats the cache and reintroduces the round trips you tried to remove.