Reducing API Latency with Apollo Client Cache Redirects
Learn how to use Apollo Client Type Policies to implement cache redirects, eliminating redundant network requests when moving from list views to detail views.
25 Jun 2026, 18:39 UTC

The Redundant Request Problem
A common pattern in GraphQL applications is the "List-to-Detail" transition. A user views a list of items (e.g., a list of Project cards) and then clicks one to view its full details. By default, Apollo Client treats the detail query as a new request, triggering a network call even if the list query already fetched the most critical fields for that specific item.
This creates a perceived lag where the UI shows a loading spinner for data the client already possesses. The solution is to implement Cache Redirects using Type Policies, allowing the client to resolve a specific object lookup by redirecting it to an existing entry in the normalized cache.
How Normalization Enables Redirects
Apollo Client uses a normalized cache, meaning it flattens nested query results into a lookup table. Each object is stored by a unique identifier, typically a combination of its __typename and an id field (e.g., Project:123).
When you query a list of Projects, Apollo populates the cache with every Project object returned. If you later request a single Project by ID, Apollo normally looks for a specific query result for that ID. If it doesn't find a matching query, it goes to the network. A Cache Redirect intercepts this process, telling Apollo: "If you can't find the query result, check if the object Project:123 already exists in the normalized store and use that instead."
Implementing a Redirect Policy
To implement this, you define a read function within the typePolicies of your InMemoryCache. This function acts as a middleware for cache lookups.
Example Configuration
Assume a schema where a Project can be fetched by an id. The following configuration should be applied during the initialization of the ApolloClient instance:
import { InMemoryCache, ApolloClient } from '@apollo/client';
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
// This redirects the 'project' query to the normalized cache
project: {
read(_, { args, toReference }) {
// args.id is the ID passed to the project(id: "...") query
return toReference({
__typename: 'Project',
id: args.id,
});
},
},
},
},
},
});
const client = new ApolloClient({
uri: 'https://your-api.com/graphql',
cache,
});
Execution Details
- Where to run: This configuration happens in the client-side initialization code.
- Permissions: No special permissions are required beyond standard JS execution.
- Placeholders:
Projectmust match the exact__typenamedefined in your GraphQL schema. - Expected Result: When
useQueryis called for a project that was already part of a previous list fetch, the data returns instantly without an HTTP request.
Trade-offs and Risks
While cache redirects improve speed, they introduce specific engineering risks:
- Partial Data (Under-fetching): If the list query only fetched the
nameandid, but the detail page requiresdescriptionandbudget, the redirect will provide the name and then trigger a network request anyway to fill the missing fields. This is usually acceptable but can lead to "pop-in" UI effects. - Stale Data: If the server state changes frequently, the user may see outdated information from the list view until the detail query eventually completes its network fetch.
- Infinite Loops: Avoid calling the same field inside a
readfunction usingreadFieldwithout a termination condition, as this can crash the browser tab.
Verifying the Implementation
To ensure the redirect is working as intended, follow these diagnostic steps:
- Network Inspection: Open the Browser DevTools Network tab. Fetch the list of items, then navigate to a detail page. If the redirect is working, you should see no new XHR/Fetch request for the detail query (or a request that only fetches missing fields).
- Cache Inspection: Use the Apollo Client DevTools. Check the "Cache" tab to verify that objects are being stored as
Project:IDrather than as nested query results. - Fallback Test: Clear the cache or refresh the page and navigate directly to the detail URL. Verify that the system correctly falls back to a network request when the cache is empty.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.