Apollo Client stores the results of its GraphQL queries in a normalized, in-memory cache. This enables your client to respond to future queries for the same data without sending unnecessary network requests.
This article describes cache setup and configuration. To learn how to interact with cached data, see Reading and writing data to the cache.
As of Apollo Client 3.0, the
InMemoryCache class is provided by the
@apollo/client package. No additional libraries are required.
InMemoryCache object and provide it to the
APOLLO_OPTIONS token, like so:
InMemoryCache constructor accepts a variety of configuration options.
Although the cache's default behavior is suitable for a wide variety of applications, you can configure its behavior to better suit your particular use case. In particular, you can:
- Specify custom primary key fields
- Customize the storage and retrieval of individual fields
- Customize the interpretation of field arguments
- Define supertype-subtype relationships for fragment matching
- Define patterns for pagination
- Manage client-side local state
To customize cache behavior, provide an
options object to the
InMemoryCache constructor. This object supports the following fields:
Include this object to define polymorphic relationships between your schema's types. Doing so enables you to look up cached data by interface or by union.
The key for each entry is the
Include this object to customize the cache's behavior on a type-by-type basis.
The key for each entry is a type's
A function that takes a response object and returns a unique identifier to be used when normalizing the data in the store.
Deprecated in favor of the
InMemoryCache normalizes query response objects before it saves them to its internal data store. Normalization involves the following steps:
- The cache generates a unique ID for every identifiable object included in the response.
- The cache stores the objects by ID in a flat lookup table.
- Whenever an incoming object is stored with the same ID as an existing object, the fields of those objects are merged.
- If the incoming object and the existing object share any fields, the incoming object overwrites the cached values for those fields.
- Fields that appear in only the existing object or only the incoming object are preserved.
Normalization constructs a partial copy of your data graph on your client, in a format that's optimized for reading and updating the graph as your application changes state.
In Apollo Client 3 and later, the
InMemoryCachenever creates a fallback, "fake" identifier for an object when identifier generation fails or is disabled.
By default, the
InMemoryCache generates a unique identifier for any object that includes a
__typename field. To do so, it combines the object's
__typename with its
_id field (whichever is defined). These two values are separated by a colon (
For example, an object with a
Task and an
14 is assigned a default identifier of
If one of your types defines its primary key with a field besides
_id, you can customize how the
InMemoryCache generates unique identifiers for that type. To do so, you define
TypePolicy for the type. You specify all of your cache's
typePolicies in the
options object you provide to the
keyFields field in relevant
TypePolicy objects, like so:
This example shows three
typePolicies: one for a
Product type, one for a
Person type, and one for a
Book type. Each
keyFields array defines which fields on the type together represent the type's primary key.
Book type above uses a subfield as part of its primary key. The
["name"] item indicates that the
name field of the previous field in the array (
author) is part of the primary key. The
author field must be an object that includes a
name field for this to be valid.
In the example above, the resulting identifier string for a
Book object has the following structure:
An object's primary key fields are always listed in the same order to ensure uniqueness.
Note that these
keyFields strings always refer to the actual field names as defined in your schema, meaning the ID computation is not sensitive to field aliases.
If you define a custom identifier that uses multiple fields, it can be challenging to calculate and provide that identifier to methods that require it (such as
To help with this, you can use the
cache.identify method to calculate the identifier for any normalized object you fetch from your cache. See Obtaining an object's custom ID.
If you need to define a single fallback
keyFields function that isn't specific to any particular
__typename, you can use the
dataIdFromObject function that was introduced in Apollo Client 2.x:
dataIdFromObjectAPI is included in Apollo Client 3.0 to ease the transition from Apollo Client 2.x. The API might be removed in a future version of
Notice that the above function still uses different logic to generate keys based on an object's
__typename. In the above case, you might as well define
keyFields arrays for the
Person types via
typePolicies. Also, this code is sensitive to aliasing mistakes, it does nothing to protect against undefined
object properties, and accidentally using different key fields at different times can cause inconsistencies in the cache.
You can instruct the
InMemoryCache not to normalize objects of a certain type. This can be useful for metrics and other transient data that's identified by a timestamp and never receives updates.
To disable normalization for a type, define a
TypePolicy for the type (as shown in Customizing identifier generation by type) and set the policy's
keyFields field to
Objects that are not normalized are instead embedded within their parent object in the cache. You can't access these objects directly, but you can access them via their parent.
To customize how the cache interacts with specific types in your schema, you can provide an object mapping
__typename strings to
TypePolicy objects when you create a new
TypePolicy object can include the following fields:
In addition to
TypePolicy can indicate that it represents the root query, mutation, or subscription type by setting
The cache normally obtains
__typename information by adding the
__typename field to every query selection set it sends to the server. It could technically use the same trick for the outermost selection set of every operation, but the
__typename of the root query or mutation is almost always simply
"Mutation", so the cache assumes those common defaults unless instructed otherwise in a
Compared to the
__typenames of entity objects like
Persons, which are absolutely vital to proper identification and normalization, the
__typename of the root query or mutation type is not nearly as useful or important, because those types are singletons with only one instance per client.
The final property within
TypePolicy is the
fields property, which is a map from string field names to
FieldPolicy objects. For more information on this field, see Customizing the behavior of cached fields.