Skip to main content
Version: 1.6.0

Decision Matrix

Use these tables when the code is "almost obvious" but one wrong persistence choice would change user behavior after reload.

set(null) vs remove() vs reset()​

NeedActionResult after reload
Keep an explicit "cleared" stateset(null)Still cleared
Forget the key entirelyremove()Falls back to defaultValue
Restore the default as a stored valuereset()Rehydrates defaultValue

Rule of thumb:

  • Use set(null) for durable clear intent.
  • Use remove() for absence.
  • Use reset() when the default itself should become the new persisted value.

Shopping Cart Semantics​

NeedRecommended representation or actionWhy
Active cart with zero itemsCartState with items: []The cart still exists and can accept new lines immediately
Explicit “no cart” or “cart unavailable” stateset(null) on CartState | nullOnly when null has real product meaning
Forget cart after checkout, logout, or recoveryremove()The next read falls back to defaultValue
Restore a seeded default cart shapereset()Re-persists the configured default object
Header badge count or subtotalDerive from cart.itemsPrevents drift between stored lines and stored summaries

Migration vs reconcile(...)​

SituationUseWhy
Stored shape changed between explicit versionsSchema migrationStructural compatibility belongs to version transitions
Every write should normalize the valueWrite-time migration (fromVersion === toVersion)Keeps writes canonical
Existing shape is fine, but defaults or policy should refreshreconcile(...)Conditional read-time rewrite without inventing a new version
Invalid or stale data should be discardedRecovery or reset flowSafer than forcing a questionable transform

Should This State Persist?​

State shapePersist?Why
Theme, density, durable layout preferenceYesUsers expect it after reload
Saved filters users intentionally restoreYesThis is durable preference state
User-authored draft contentUsually yesLost work is expensive
Hover, focus, drag, loading, optimistic flagsNoRehydrating runtime-only UI feels wrong
Temporary dirtiness and validation errorsNoThese describe a session, not durable intent
Server response cache timestampsUsually noPrefer cache logic over UI persistence
Access tokens, refresh tokens, session secretsNoThese are credentials, not durable UI state
Safe per-user drafts or saved filtersConditionallyScope them to the authenticated user and clear them on auth loss

SSR Mode Choice​

NeedConfig
Default SSR behaviorNo SSR config
Deterministic server placeholderssr.serverValue
Delay persisted read until after mountssr.hydration: "client-only"
Make every key inherit delayed hydrationMnemonicProvider ssr={{ hydration: "client-only" }}

Storage Adapter Choice​

NeedRecommended path
Standard browser persistenceDefault provider storage (localStorage)
Per-tab persistencestorage={window.sessionStorage}
Custom backend with synchronous facadeProvide a StorageLike wrapper
Cross-tab sync on a custom backendImplement storage.onExternalChange(...)
Direct async reads or writes from the hook contractNot supported in beta 1

Auth Cleanup Choice​

NeedRecommended path
Forget auth-scoped private state on logout or expiryClear the authenticated namespace before swap, or use a temporary recovery boundary for the last user namespace
Keep an explicit cleared value for the same authenticated userset(null)
Restore a known default for the same authenticated userreset()
Prevent user A data from appearing for user Buser-aware namespace such as app.user.${userId}
Enforce auth policy when stale data is read backreconcile(...) plus event-based cleanup

See Auth-Aware Persistence for the full logout, expiry, and cross-tab cleanup pattern.