GitHub

Persist

The persist field declares which state keys survive page refreshes. Everything else resets. The list is explicit — nothing is persisted unless it is named here, and sensitive data should never appear in it.

Declaring persistence

persist is an array of dot-path strings. Each path points to a key in state that should be saved:

export default {
  route: '/settings',
  state: {
    theme:       'light',
    fontSize:    16,
    sidebarOpen: true,
    user: {
      name:        '',
      preferences: { notifications: true, newsletter: false },
    },
  },
  persist: [
    'theme',
    'fontSize',
    'user.preferences',
  ],
  // ...
}

In this example, theme, fontSize, and the entire user.preferences sub-object are saved to localStorage. The sidebarOpen key and user.name are session-only — they reset on each visit.

How it works

On every state update, Pulse serialises the persisted keys and writes them to localStorage under a key derived from the page route. On the next mount, persisted values are read back and merged over the spec's initial state before the view renders.

StepWhat happens
First visitState initialised from spec.state. Nothing in storage yet.
User interactsMutations update state. Persisted keys are written to localStorage.
Page refresh / return visitPersisted values loaded from storage and merged over initial state. View renders with restored state.

Dot-path notation

Persist keys use the same dot-path notation as validation. Entire top-level keys or specific nested sub-objects can be persisted:

persist: [
  'theme',                    // top-level key
  'user.preferences',         // nested sub-object (entire object is saved)
  'cart.items',               // array of cart items
]
When persisting a nested path like user.preferences, the entire value at that path is saved and restored — not individual sub-keys within it.

Storage key

Pulse stores persisted state under pulse:[route] in localStorage. For example, a spec with route: '/settings' uses the key pulse:/settings. This namespacing prevents collisions between pages.

SSR and persistence

On the server, localStorage does not exist. The server always renders with the spec's initial state. Persisted values are applied on the client after hydration — before the first mutation, after mount.

If SSR and client state diverge significantly due to persisted values, a content flash may occur. Best practice: keep persisted state to preferences and settings that do not affect the main page content.

Clearing persisted state

To clear persisted state programmatically, remove the relevant key from localStorage:

localStorage.removeItem('pulse:/settings')

Or use a mutation that resets the persisted fields to their initial values — Pulse will save the reset values on the next update.

Best practices

  • Persist preferences and settings (theme, language, layout choices)
  • Persist shopping cart contents or draft form data
  • Never persist sensitive data (tokens, passwords, PII) — localStorage is not secure storage
  • Never persist data that must be authoritative — use server data for anything that should be fresh from the server
  • Keep persisted payloads small — localStorage has a ~5 MB limit and blocks the main thread if abused