Skip to content

Reactive Storage ​

useStorage() — the core composable. Works with localStorage, sessionStorage, and an in-memory fallback.

ts
useStorage<T>(key: string, options: StorageOptions<T>): UseStorageReturn<T>

Options ​

defaultValue ​

T

Value returned when the key is absent or has expired.

target ​

'local' | 'session' | 'memory' | 'indexeddb' · default: 'local'

Storage backend. 'indexeddb' stores through a single dedicated object store (db vue-storage-kit, store kv) — for custom databases/stores or secondary indexes, use useIndexedDB() / useIDBRef() instead.

ttl ​

number

Time-to-live in milliseconds; 0 or omitted = no expiry.

version ​

number · default: 1

Schema version of the stored data.

migrations ​

Migration[] · default: []

Migration functions run when stored version differs from version — see Schema migrations.

encrypt ​

boolean | EncryptOptions · default: false

Enable AES-GCM encryption — see Encryption.

compress ​

boolean | CompressOptions · default: false

Compress the stored envelope via the Compression Streams API. Applied before encrypt, so compression still works on the plaintext (compressed ciphertext yields no size benefit) — see Compression.

sign ​

boolean | SignOptions · default: false

HMAC-SHA256 check, applied as the outermost layer (wraps compressed/encrypted data too). Detects accidental corruption without requiring secrecy — not a defense against a user editing their own storage — see Corruption detection — combine with encrypt for both.

sync ​

boolean | SyncOptions · default: false

Enable cross-tab sync via BroadcastChannel — see Tab sync.

debounce ​

number

Coalesce writes: only persist debounce ms after the last change. Mutually exclusive with throttle (throttle wins if both are set) — setting both triggers a dev-mode console.warn at construction.

throttle ​

number

Write at most once every throttle ms even during continuous changes, instead of only after they stop.

history ​

number

Keep up to this many past values in memory for undo()/redo(). Not persisted — resets on reload.

evictOnQuota ​

boolean | { max?: number } · default: false

On QuotaExceededError, if sweeping this adapter's expired-TTL entries isn't enough, evict its least-recently-written other keys (oldest first, up to max, default 1) and retry. Off by default — deleting unrelated keys is a real side effect.

serializer ​

Serializer<T> · default: JSON serializer

Custom serialize / deserialize pair.

onError ​

(err: StorageError) => void

Called instead of throwing on quota exceeded, parse errors, crypto errors, invalid signatures, or other write failures.

onExpire ​

(key: string) => void

Called when a TTL-expired key is removed on read.

onMigrate ​

(from: number, to: number) => void

Called after a successful migration.

Return value ​

value ​

Ref<T>

Reactive two-way binding; assigning writes to storage.

isReady ​

Ref<boolean>

false until the initial async read completes (important for IndexedDB and encrypted values).

error ​

Ref<StorageError | null>

Last error, null if none.

expiry ​

ComputedRef<Date | null>

When the key expires, null if no TTL.

canUndo ​

ComputedRef<boolean>

Whether undo() currently does anything (always false unless history is set).

canRedo ​

ComputedRef<boolean>

Whether redo() currently does anything (always false unless history is set).

remove ​

() => void

Delete the key from storage and reset value to defaultValue.

refresh ​

() => Promise<void>

Re-read from storage (useful if another process may have written).

undo ​

() => void

Navigate back through values recorded via history; a no-op if history isn't set or the undo stack is empty.

redo ​

() => void

Navigate forward through values recorded via history; a no-op if history isn't set or the redo stack is empty.

Examples ​

Basic read/write:

ts
const { value: counter } = useStorage('counter', { defaultValue: 0 })

counter.value++ // writes to localStorage immediately

Session storage:

ts
const { value: token } = useStorage('auth-token', {
  defaultValue: '',
  target: 'session',
})

TTL — auto-expire after 30 minutes:

ts
const { value: cache, expiry } = useStorage('search-cache', {
  defaultValue: [] as string[],
  ttl: 30 * 60 * 1000,
  onExpire: (key) => console.log(`${key} expired`),
})

console.log(expiry.value) // Date | null

Error handling:

ts
const { value, error } = useStorage('data', {
  defaultValue: {},
  onError: (err) => {
    if (err.type === 'quota-exceeded') showToast('Storage is full')
    if (err.type === 'parse-error') console.warn('Corrupted value, reset to default')
  },
})

Custom serializer:

ts
import type { Serializer } from 'vue-storage-kit'

const base64Serializer: Serializer<string> = {
  serialize: (v) => btoa(v),
  deserialize: (raw) => atob(raw),
}

const { value } = useStorage('encoded', {
  defaultValue: '',
  serializer: base64Serializer,
})

useLocalStorage / useSessionStorage ​

Shorthand composables — identical to useStorage but with target pre-set and defaultValue as the second argument (vueuse-compatible signature).

ts
useLocalStorage<T>(key: string, defaultValue: T, opts?): UseStorageReturn<T>
useSessionStorage<T>(key: string, defaultValue: T, opts?): UseStorageReturn<T>
ts
import { useLocalStorage, useSessionStorage } from 'vue-storage-kit'

const { value: settings } = useLocalStorage('settings', { theme: 'light', lang: 'en' })
const { value: draft } = useSessionStorage('draft', '')

These are drop-in replacements for @vueuse/core useLocalStorage / useSessionStorage.

defineStorageKey ​

A typed, reusable key descriptor — define a key's shape and options once, then pass the descriptor to useStorage() directly instead of repeating key/options at every call site.

ts
function defineStorageKey<T>(key: string, options: StorageOptions<T>): StorageKeyDef<T>

useStorage() accepts either the usual (key, options) pair or a single StorageKeyDef<T>:

ts
useStorage<T>(key: string, options: StorageOptions<T>): UseStorageReturn<T>
useStorage<T>(def: StorageKeyDef<T>): UseStorageReturn<T>
ts
import { defineStorageKey, useStorage } from 'vue-storage-kit'

// Define once, e.g. in a shared keys.ts module
const themeKey = defineStorageKey('theme', {
  defaultValue: 'light' as 'light' | 'dark',
  ttl: undefined,
})

// Use anywhere, fully typed, without repeating the options
const { value: theme } = useStorage(themeKey)