HomeBytesheetsRoadmapsUI TemplatesUI ToolsStack Discussion
8 Topics
Chapter•90 Minutes

Caching, Optimistic UI & Client Data Management

Learn how GraphQL clients cache server data, normalize entities, update cached results after mutations, and provide responsive optimistic interfaces.

Why GraphQL Clients Need Caching

A GraphQL client frequently requests data that has already been fetched. Without caching, navigating between screens or rendering multiple components that need the same entity can cause unnecessary network requests.

Client-side caching allows previously fetched GraphQL data to be reused. This can reduce latency, decrease server load, and make applications feel more responsive.

Normalized GraphQL Caches

A normalized cache stores entities independently rather than keeping every query result as an isolated copy.

For example, a user returned by several different queries can be represented as one cached entity identified by a stable key such as User:42. When that entity changes, multiple views can automatically observe the updated cached value.

Normalization is particularly useful for applications where the same entities appear in many queries.

Understanding Fetch Policies

GraphQL clients such as Apollo Client provide different strategies for deciding whether to read from the cache, contact the server, or combine both approaches.

A cache-first strategy prefers existing cached data. A network-only strategy always requests fresh data. A cache-and-network strategy can display cached data immediately and then update it with a network response.

The correct policy depends on the freshness requirements of the specific data.

Updating the Cache After Mutations

A successful mutation does not automatically mean that every affected cached query is correct. The client may need to update or invalidate cached data.

For example, creating a new task may require inserting the task into a cached task list. Deleting a task may require removing it from cached lists. Updating a user may require updating the normalized user entity.

Good GraphQL client design considers the relationship between every mutation and the queries whose results it changes.

Optimistic UI

Optimistic UI updates the interface before the server confirms the operation. The client assumes that the mutation will succeed and immediately updates the local representation.

For example, when a user clicks a like button, the UI can immediately increment the count instead of waiting for the network response. If the mutation fails, the client rolls the change back.

Optimistic updates work best for operations with predictable outcomes and small, reversible changes.

Optimistic Mutation Lifecycle

A typical optimistic mutation follows four stages: capture the current state, apply the optimistic result, send the mutation to the server, and reconcile the final server response.

If the server succeeds, the optimistic state is replaced or confirmed by authoritative server data. If the server fails, the client restores the previous state and displays appropriate feedback.

Optimistic Mutation Flow

Cache Consistency and Invalidation

Caching introduces a consistency problem: cached data can become stale while the server contains newer data.

Applications can address this through explicit cache updates, refetching, time-based policies, subscriptions, polling, cache invalidation, or server-driven events.

There is no universally correct caching policy. Highly dynamic data often requires more aggressive revalidation, while relatively stable data can remain cached for longer.

Check Your Understanding

Test your understanding of normalized GraphQL caching.

Knowledge Check

What is a major advantage of a normalized GraphQL cache?