svelte-persisted-state Svelte Themes

Svelte Persisted State

A small, robust utility for reactive, persisted state in Svelte, with first-class support for debouncing, tab synchronization, and custom storage behavior. Designed to feel like normal Svelte state — just persistent.

svelte-persisted-state

A small, robust utility for reactive, persisted state in Svelte, with first-class support for debouncing, tab synchronization, and custom storage behavior.

Designed to feel like normal Svelte state — just persistent.


Features

  • ✅ Reactive persisted state
  • 💾 localStorage, sessionStorage, or custom Storage
  • 🔄 Optional cross-tab synchronization
  • ⏱️ Optional debounced persistence
  • 🧠 Safe defaults with full customization
  • 🧪 SSR-safe (no storage access on the server)

Installation

npm install svelte-persisted-state

or

pnpm add svelte-persisted-state

Basic Usage

import { persisted } from 'svelte-persisted-state';

const counter = persisted('counter', 0);

counter.value += 1;
  • The value is automatically persisted to localStorage
  • On reload, the stored value is restored
  • Updates are reactive and tracked by Svelte

Reactive Usage in Svelte

<script lang="ts">
  import { persisted } from 'svelte-persisted-state';

  const theme = persisted('theme', 'light');
</script>

<button on:click={() => theme.value = 'dark'}>
  Dark mode
</button>

<p>Current theme: {theme.value}</p>

API

persisted<T>(key, fallback, behavior?)

Creates (or retrieves) a persisted, reactive state bound to a storage key.

function persisted<T>(
  key: string,
  fallback: T,
  behavior?: CustomBehavior<T>
): PersistedState<T>;

Parameters

  • key The storage key used to persist the value.

  • fallback The value used when no stored value exists or parsing fails.

  • behavior (optional) Configuration controlling serialization, storage backend, synchronization, and persistence timing.


Returned Value: PersistedState<T>

type PersistedState<T> = {
  value: T;
  persist(debounce?: number | false): void;
  destroy(): void;
  readonly key: string;
};

.value

The reactive value.

state.value = newValue;
  • Mutations trigger persistence (if enabled)
  • Deep object mutations are tracked

.persist(debounce?)

Manually persists the current value to storage.

state.persist();
state.persist(300);
  • Clears any pending debounced persistence
  • Does not update .value
  • Errors during serialization are forwarded to onStringifyError
  • No-op during server-side rendering

.destroy()

Cleans up all side effects and removes the stored value.

state.destroy();
  • Removes internal listeners and reactive effects
  • Deletes the stored value for this key
  • The instance should not be used afterward

Behavior Configuration

The behavior object allows fine-grained control over persistence.

const state = persisted('user', null, {
  storage: sessionStorage,
  debounce: 250,
  syncTabs: false
});

Available Options

Option Type Default Description
storage Storage localStorage Storage backend
parse (string) => T JSON.parse Deserialize stored value
stringify (T) => string JSON.stringify Serialize value
onParseError (unknown) => void remove item Called when parsing fails
onStringifyError (unknown) => void no-op Called when serialization fails
debounce number | false false Debounce persistence on value changes
persistOnValueChange boolean false Persist when value changes
persistOnTabChange boolean true Persist when tab becomes hidden
syncTabs boolean true Sync value across tabs

Debouncing Persistence

Debouncing applies only to persistence triggered by value changes.

const search = persisted('search', '', {
  debounce: 300
});
  • Rapid updates are coalesced into a single write
  • Manual .persist() calls are never debounced
  • Tab-hide persistence is never debounced

Cross-Tab Synchronization

When syncTabs is enabled (default):

  • Changes in one tab update all other tabs
  • Uses the browser storage event
  • Parsing errors fall back safely

Server-Side Rendering (SSR)

  • Storage is never accessed on the server
  • Fallback values are always used
  • Persistence resumes automatically in the browser

Caching Behavior

Calling persisted() multiple times with the same key and storage returns the same instance:

persisted('theme', 'light') === persisted('theme', 'light');
// true

This prevents duplicate listeners and keeps state consistent.


License

MIT


Top categories

Loading Svelte Themes