Skip to content

vue-storage-kit

Reactive localStorage, sessionStorage, IndexedDB and cookies for Vue 3 (and React) — TTL, AES-GCM encryption, HMAC signing, schema migrations with up/down functions, undo/redo, and cross-tab sync — built on a framework-agnostic core, with Vue and React as thin bindings over it.

Features

  • useStorage — unified reactive state over localStorage, sessionStorage, IndexedDB, or an in-memory store; drop-in replacement for vueuse useLocalStorage / useSessionStorage. Available for Vue (a Ref) and React (a useSyncExternalStore-backed hook) — both are thin bindings over the same framework-agnostic engine
  • Schema migrations — versioned data with up / down migration chains; runs automatically on version mismatch, writes back the migrated value
  • TTL — optional time-to-live per key; lazy expiry checked on every read, no timers; manual cleanExpired() sweep for startup cleanup
  • AES-GCM encryption — Web Crypto API (crypto.subtle), key derived from a password via PBKDF2 or supplied as a CryptoKey; salt + IV + ciphertext packed into a single base64 string; derived key cached in session memory; reencrypt()/rotateEncryptedKey() to rotate a password without data loss
  • HMAC signing — lightweight accidental-corruption detection (sign: { password }) for data that doesn't need to be secret; not a defense against a user editing their own browser's storage (see Corruption detection) — combine with encrypt for confidentiality + integrity
  • Undo / redohistory: n keeps the last n values in memory; undo() / redo() navigate them (not persisted across reloads)
  • Debounce & throttledebounce coalesces writes after a pause; throttle guarantees a write at most every n ms during continuous changes (a slider, a drag)
  • Resilient writes — on QuotaExceededError, sweeps this adapter's own expired-TTL entries and retries once; opt into evictOnQuota to additionally evict the least-recently-written other keys. Non-quota write errors are reported via onError, not thrown from inside a reactive callback
  • Cross-tab syncBroadcastChannel with storage event fallback; last-write-wins conflict resolution by timestamp; optional leader election via navigator.locks
  • useIndexedDB — promise-based key-value API plus a reactive useIDBRef for a single key; or just pass target: 'indexeddb' to useStorage() for the same TTL/migrations/encrypt/compress/sync pipeline as any other target
  • useCookie — reactive cookies with expires, sameSite, secure; client-only from the package root, or SSR-aware (H3-backed on the server, supports httpOnly) when auto-imported inside the Nuxt module
  • Vue plugin — global prefix, default target/serializer/encrypt, and a global error handler, all applied to every useStorage() call
  • Nuxt module — auto-imports all composables; wires up the plugin with runtime config
  • Serializer — JSON with round-trip support for Date, Map, Set, and undefined; bring your own serializer via the Serializer<T> interface
  • SSR-safe — falls back to in-memory storage when window is unavailable; isReady ref lets components show a skeleton until hydration
  • Devtools — a custom Vue Devtools inspector and timeline over every live useStorage() instance (Vue or React) — current value, target, TTL, undo/redo state, plus a log of write/expire/migrate/sync events; /devtools entry point, opt-in via setupDevtools(app)
  • Testing utilities/testing entry point: mockStorage(), resetStorageState(), seedEnvelope()/seedExpiredEnvelope(), flushAsync() — the patterns this package's own test suite uses, packaged for your tests
  • Vue and React as optional peers@vue/devtools-api is the sole required runtime dependency (used only if you call setupDevtools); neither vue nor react is required by the package itself, only by the entry point you actually import. /crypto, /sync, /compress, /pinia, /devtools, /react, /testing are separate tree-shakeable entry points

Installation

bash
npm install vue-storage-kit

For Vue, install Vue itself (optional peer — only needed if you import from the package root or any Vue-specific composable):

bash
npm install vue@>=3.3

For React (vue-storage-kit/react), install React instead — you don't need vue at all:

bash
npm install react@>=18

Quick start

vue
<script setup lang="ts">
import { useLocalStorage } from 'vue-storage-kit'

const { value: theme } = useLocalStorage('theme', 'light')
</script>

<template>
  <button @click="theme = theme === 'light' ? 'dark' : 'light'">Current theme: {{ theme }}</button>
</template>

The value is persisted to localStorage and is reactive — changing theme.value writes to storage immediately.