A persister for synchronous storages, to be used with TanStack/Query
npx @tessl/cli install tessl/npm-tanstack--query-sync-storage-persister@5.86.0TanStack Query Sync Storage Persister provides a synchronous storage persister for TanStack Query that enables caching and persistence of query data to synchronous storage systems like localStorage or sessionStorage. It implements throttled persistence with configurable serialization, retry logic, and error handling.
npm install @tanstack/query-sync-storage-persisterimport { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";For CommonJS:
const { createSyncStoragePersister } = require("@tanstack/query-sync-storage-persister");import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
import { persistQueryClient } from "@tanstack/query-persist-client-core";
import { QueryClient } from "@tanstack/query-core";
// Create a query client
const queryClient = new QueryClient();
// Create a persister with localStorage (uses default key 'REACT_QUERY_OFFLINE_CACHE')
const persister = createSyncStoragePersister({
storage: window.localStorage,
throttleTime: 2000, // Throttle saves to 2 seconds
});
// Setup persistence
persistQueryClient({
queryClient,
persister,
buster: "v1.0", // Cache buster string
});The package provides a single main export that creates a Persister object compatible with TanStack Query's persistence system:
Creates a synchronous storage persister for TanStack Query persistence.
/**
* @deprecated use `createAsyncStoragePersister` from `@tanstack/query-async-storage-persister` instead.
*/
function createSyncStoragePersister(
options: CreateSyncStoragePersisterOptions
): Persister;
interface CreateSyncStoragePersisterOptions {
/** The storage client used for setting and retrieving items from cache.
* For SSR pass in `undefined`. Note that window.localStorage can be
* `null` in Android WebViews depending on how they are configured.
*/
storage: Storage | undefined | null;
/** The key to use when storing the cache */
key?: string;
/** To avoid spamming,
* pass a time in ms to throttle saving the cache to disk */
throttleTime?: number;
/**
* How to serialize the data to storage.
* @default `JSON.stringify`
*/
serialize?: (client: PersistedClient) => string;
/**
* How to deserialize the data from storage.
* @default `JSON.parse`
*/
deserialize?: (cachedString: string) => PersistedClient;
/** Retry strategy for handling storage errors */
retry?: PersistRetryer;
}Usage Examples:
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
import { removeOldestQuery } from "@tanstack/query-persist-client-core";
// Basic usage with localStorage
const persister = createSyncStoragePersister({
storage: window.localStorage,
});
// Custom configuration
const customPersister = createSyncStoragePersister({
storage: window.sessionStorage,
key: "custom-app-cache",
throttleTime: 5000, // 5 second throttle
serialize: (data) => JSON.stringify(data, null, 2),
deserialize: (str) => JSON.parse(str),
retry: removeOldestQuery, // Remove oldest queries when storage is full
});
// Server-side rendering safe (no storage)
const ssrPersister = createSyncStoragePersister({
storage: undefined, // Returns no-op functions
});interface Storage {
getItem: (key: string) => string | null;
setItem: (key: string, value: string) => void;
removeItem: (key: string) => void;
}
interface Persister {
persistClient: (persistClient: PersistedClient) => Promisable<void>;
restoreClient: () => Promisable<PersistedClient | undefined>;
removeClient: () => Promisable<void>;
}
interface PersistedClient {
timestamp: number;
buster: string;
clientState: DehydratedState;
}
type PersistRetryer = (props: {
persistedClient: PersistedClient;
error: Error;
errorCount: number;
}) => PersistedClient | undefined;
type Promisable<T> = T | PromiseLike<T>;
// Imported from @tanstack/query-core
interface DehydratedState {
mutations: Array<any>;
queries: Array<any>;
}When storage operations fail, the persister uses the configured retry strategy:
import { removeOldestQuery } from "@tanstack/query-persist-client-core";
const persister = createSyncStoragePersister({
storage: window.localStorage,
retry: removeOldestQuery, // Removes oldest cached queries when storage is full
});If no retry strategy is provided and storage fails, the operation is silently ignored. When storage is not available (SSR, private browsing, etc.), the persister returns no-op functions that safely do nothing.
// Persist to localStorage with custom settings
const persister = createSyncStoragePersister({
storage: window.localStorage,
key: "my-app-v1.2",
throttleTime: 1000,
});import { removeOldestQuery } from "@tanstack/query-persist-client-core";
// Handle storage quota exceeded errors
const persister = createSyncStoragePersister({
storage: window.localStorage,
retry: removeOldestQuery, // Remove old queries when storage is full
});// Custom serialization for complex data types
const persister = createSyncStoragePersister({
storage: window.localStorage,
serialize: (data) => {
// Custom serialization logic
return JSON.stringify(data, (key, value) => {
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
return value;
});
},
deserialize: (str) => {
// Custom deserialization logic
return JSON.parse(str, (key, value) => {
if (value && value.__type === 'Date') {
return new Date(value.value);
}
return value;
});
},
});