persist
Persist chunk state to localStorage or any Web Storage API.
persist() wraps an existing chunk and automatically syncs its value to a storage backend — localStorage by default. The persisted value is loaded back on initialization, so state survives page refreshes.
import { chunk } from "stunk";
import { persist } from "stunk/middleware";
const theme = chunk<"light" | "dark">("light");
const persistedTheme = persist(theme, { key: "app-theme" });
persistedTheme.set("dark");
// stored in localStorage under "app-theme"
// On next page load — automatically restored to "dark"API reference
persist() returns a PersistedChunk<T> — the same Chunk<T> interface plus one additional method:
clearStorage()
Removes the persisted key from storage without destroying the chunk. Useful for logout or cache invalidation:
persistedTheme.clearStorage();
// localStorage key removed — chunk still works normallyOptions
| Option | Type | Default | Description |
|---|---|---|---|
key | string | required | The storage key |
storage | Storage | localStorage | Any object implementing the Web Storage API |
serialize | (value: T) => string | JSON.stringify | Custom serializer |
deserialize | (value: string) => T | JSON.parse | Custom deserializer |
onError | (error, operation) => void | — | Called on load/save errors and type mismatches |
Error handling
persist catches and logs errors from both loading and saving. A corrupt storage entry won't crash your app — the chunk falls back to its initial value. Pass onError to handle errors yourself:
const persistedTheme = persist(theme, {
key: "app-theme",
onError: (error, operation) => {
console.error(`Persist ${operation} failed:`, error.message);
},
});operation is either 'load' or 'save'. onError is also called when the stored value has a different type than the initial chunk value — for example, if an array was stored but the chunk expects an object.
Custom storage
Pass any object implementing the Web Storage API — for example sessionStorage:
const sessionTheme = persist(theme, {
key: "app-theme",
storage: sessionStorage,
});Custom serialization
For values that don't serialize cleanly with JSON.stringify:
const lastVisited = chunk(new Date());
const persisted = persist(lastVisited, {
key: "last-visited",
serialize: (date) => date.toISOString(),
deserialize: (str) => new Date(str),
});SSR safety
persist detects server environments automatically — if localStorage is not available, it logs a warning and returns the base chunk unchanged. No crash, no setup needed.
If you want persistence in SSR, pass a custom storage implementation that works server-side:
const persisted = persist(theme, {
key: "app-theme",
storage: myServerSideStorage,
});Composing with other middleware
persist composes naturally with history and chunk middleware:
import { chunk } from "stunk";
import { logger } from "stunk/middleware";
import { history, persist } from "stunk/middleware";
const count = chunk(0, { middleware: [logger()] });
const tracked = history(count);
const persisted = persist(tracked, { key: "count" });
// logger on every set(), history tracking, and persistence — all active