Apollo Client cache persistence: schema version mismatch during hydration
0 reputation · 11 Nov 2023, 21:01 UTC
0 reputation · 11 Nov 2023, 21:01 UTC
Apollo Client utilizes apollo3-cache-persist to mirror the in-memory cache to local storage, enabling state recovery across browser sessions. During the hydration phase, the client restores the persisted state to the InMemoryCache before the application becomes interactive.
A challenge arises when the application schema is updated between sessions. If the persisted cache contains data structures or fields that are incompatible with the current schema version, the hydration process may lead to inconsistent state or runtime errors when the cache is accessed.
While corrupted storage can be handled via error catching, there is no built-in mechanism to detect a version mismatch between the stored cache and the active client schema.
33275 reputation · 11 Nov 2023, 21:39 UTC
Apollo Client and apollo3-cache-persist do not provide a native versioning system for persisted state. The InMemoryCache assumes that the data restored from local storage conforms to the current schema and normalization rules. When the schema changes—such as renaming fields or altering type structures—the hydration process may inject stale or incompatible data into the cache, leading to runtime errors or UI inconsistencies.
The most reliable strategy is to implement a manual version check during the application's initialization phase, before the persistCache call is executed. By storing a version identifier alongside the cache data, you can determine if the persisted state is compatible with the current build.
Implementation Steps:
CACHE_VERSION in your application configuration.persistCache, retrieve the stored version from local storage.CACHE_VERSION.localStorage.clear() or removing the specific cache key) before proceeding with hydration.const CACHE_VERSION = '1.2.0';
const STORED_VERSION = localStorage.getItem('apollo-cache-version');
if (STORED_VERSION !== CACHE_VERSION) {
localStorage.removeItem('apollo-cache-persist');
localStorage.setItem('apollo-cache-version', CACHE_VERSION);
}
// Proceed to persistCache()...
Apollo Client does not provide a native mechanism to partially invalidate specific types or fields during the restore process of apollo3-cache-persist. The persistence layer treats the cache as a serialized blob of the normalized store. If you require partial invalidation, you must manually transform the persisted JSON object before it is passed back into the InMemoryCache, or utilize cache.evict() and cache.gc() immediately after hydration to prune known stale entities.
This approach assumes the use of apollo3-cache-persist and a standard InMemoryCache setup. To verify a mismatch is occurring, inspect the local storage entry for your cache and compare the JSON keys against your current GraphQL fragment definitions.
Diagnostic Detail Needed: Are you using a custom dataIdFromObject function? If your normalization logic has changed, the cache is structurally invalid regardless of the schema version, and a full clear is mandatory.
Use comments to ask for clarification. Post a solution as an answer.
5,460 reputation · 12 Nov 2023, 07:20 UTC
When you call persistCache you can pass a schemaVersion option (e.g., schemaVersion: '1.2.0'). The library stores this value together with the serialized cache under the key __APOLLO_CACHE_PERSISTED__. During hydration it reads the persisted blob, extracts the stored version and compares it to the option you supplied. A mismatch causes the persisted cache to be discarded and a development‑mode warning to be logged, forcing a fresh cache initialization.