Skip to content

valtiojs/valtio-persist

Repository files navigation

NPM Version GitHub Actions Workflow Status npm bundle size NPM License

valtio-persist

A persistence layer for valtio that allows you to save and restore state to various storage backends.

Features

  • πŸ”„ Persist and restore valtio state automatically
  • 🧩 Pluggable storage backends (localStorage, sessionStorage, IndexedDB, memory)
  • πŸ”€ Customizable merge strategies (default shallow merge, deep merge)
  • πŸ”’ Extensible serialization (JSON by default, add encryption, compression)
  • ⏱️ Configurable debounce for performance optimization
  • 🚫 Conditional persistence with shouldPersist option
  • πŸš€ TypeScript support with full type safety

Installation

npm install valtio-persist
# or
yarn add valtio-persist
# or
pnpm add valtio-persist

Basic Usage

import { persist } from 'valtio-persist'

// Define your state
interface State {
  count: number
  text: string
  user?: {
    name: string
    loggedIn: boolean
  }
}

// Create a persisted store
const { store } = await persist<State>(
  // Initial state
  { 
    count: 0, 
    text: 'Hello' 
  },
  // Storage key
  'my-app-state'
)

// Use the store like a regular valtio store
store.count++
store.text = 'Updated'
store.user = { name: 'John', loggedIn: true }

// The changes will be automatically persisted to localStorage

Advanced Usage

Storage Strategies

import { persist, LocalStorageStrategy } from 'valtio-persist'

// Use localStorage (default)
const { store: localStore } = await persist(
  { count: 0 },
  'local-store',
  { storageStrategy: LocalStorageStrategy }
)

LocalStorageStrategy is the default and is provided within the main valtio-persist bundle along with SessionStorageStrategy and MemoryStoragStrategey (useful for testing). Other strategies are imported separately. Many of these are still in development. See Future Additions.

import { persist } from 'valtio-persist'
import { IndexedDbStrategy } from 'valtio-persist/indexed-db'

const { store } = await persist(
  { count: 0 },
  'my-indexdb-store',
  { storageStrategy: IndexedDbStrategy }
)

Current list of available storage strategies. You can find others that are still in development in Future Additions

Exported NameImport syntax
local-storage
import { LocalStorageStrategy } from 'valtio-persist'
session-storage
import { SessionStorageStrategy } from 'valtio-persist'
memory-storage
import { MemoryStorageStrategy } from 'valtio-persist'
The items below are not included in the `valtio-persist` bundle
indexed-db
import { IndexedDBStrategy } from 'valtio-persist/indexed-db'
Many more coming! See Future Additions

Merge Strategies

Choose how to merge stored state with the initialState.

The default merge strategy doesn't check for any non-serializable types which in turn is very fast. If you're just store simple objects, use this strategy.

The deepMerge strategy will go through the object and account for unserializable types and store them as best it can.

import { persist } from 'valtio-persist'
import { DefaultMergeStrategy, DeepMergeStrategy } from 'valtio-persist'

// Use default (shallow) merge strategy
const { store: defaultStore } = await persist(
  { count: 0, nested: { value: 'default' } },
  'default-merge',
  { mergeStrategy: DefaultMergeStrategy }
)

// Use deep merge strategy for nested objects
const { store: deepStore } = await persist(
  { count: 0, nested: { value: 'default', other: true } },
  'deep-merge',
  { mergeStrategy: DeepMergeStrategy }
)

Conditional Persistence

import { persist } from 'valtio-persist'

// Only persist when specific conditions are met
const { store } = await persist(
  { count: 0, saving: false },
  'conditional-store',
  {
    // Only persist when count is even and we're not in a saving state
    shouldPersist: (prevState, nextState) => 
      nextState.count % 2 === 0 && !nextState.saving
  }
)

Debounce Persistence

Note: This is not recommended for file writes. Consider throttling instead.

import { persist } from 'valtio-persist'

// Set custom debounce time (default is 100ms)
const { store } = await persist(
  { count: 0 },
  'debounced-store',
  { debounceTime: 500 } // Wait 500ms after state changes before persisting
)

Manual Control

Restoration and persistence are automatically handled for you, but you can manually invoke them as well.

import { persist } from 'valtio-persist'

// Get manual control functions
const { store, persist: persistStore, restore, clear } = await persist(
  { count: 0 },
  'manual-store'
)

// Manually trigger persistence
await persistStore()

// Manually restore from storage
const success = await restore()
if (success) {
  console.log('State restored successfully')
}

// Clear persisted state
await clear()

Options Object Format

import { persist } from 'valtio-persist'
import { SessionStorageStrategy, DeepMergeStrategy } from 'valtio-persist'

const { store } = await persist(
  { count: 0 },
  'storage-key',
  {
    storageStrategy: SessionStorageStrategy,
    mergeStrategy: DeepMergeStrategy,
    debounceTime: 200,
    shouldPersist: (prev, next) => true
  }
)

TypeScript Support

The library is fully typed and will respect your state interface:

interface UserState {
  name: string
  loggedIn: boolean
  preferences: {
    theme: 'light' | 'dark'
    notifications: boolean
  }
}

// Type-safe persisted store
const { store } = await persist<UserState>(
  {
    name: '',
    loggedIn: false,
    preferences: {
      theme: 'light',
      notifications: true
    }
  },
  'user-settings'
)

// TypeScript will provide autocomplete and type checking
store.name = 'John' // βœ…
store.preferences.theme = 'dark' // βœ…
store.preferences.theme = 'blue' // ❌ Type error

Future additions

We have many new storage strategies already in the works and would love the help of the community (that's you) to both test and develop them. Each of the items below already has it's own branch. Contributions are most welcome!

async-storage - React Native persistent key-value storage system for mobile apps.

expo-file-system - File-based storage for Expo applications with directory support.

extension-storage - Browser extension-specific storage using Chrome's storage API.

file-system-api - Modern web browser API for accessing the file system in PWAs (progressive web apps).

single-file - Node.js implementation that stores all state in a single JSON file. (from the original valtio-persist libarary)

multi-file - Node.js implementation that stores each state key in a separate file. (from the original valtio-persist library)

secure-storage - Encrypted storage for sensitive data in mobile apps using Expo or React Native.

sqllite - Relational database storage using SQLite for more complex data relationships.

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Thank you

A big shout and thank you to Noitidart who created the original valtio-persist package and has graciously allowed the use of the name to the community.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published