Skip to content

Migration from persist()

Migrating from Zustand’s persist() to zod-vault’s vault() is straightforward.

import { create } from "zustand";
import { persist } from "zustand/middleware";
const useStore = create(
persist(
(set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 })),
}),
{ name: "my-store" }
)
);
import { create } from "zustand";
import { vault } from "@zod-vault/zustand";
const useStore = create(
vault(
(set) => ({
count: 0,
increment: () => set((s) => ({ count: s.count + 1 })),
}),
{
name: "my-store",
recoveryKey: "ABCD-EFGH-...", // Add this
}
)
);

That’s it. Your data is now encrypted at rest.

persist()vault()Notes
namenameSame
storagestorageCompatible
partializepartializeSame
mergemergeSame
onRehydrateStorageonRehydrateStorageSame
skipHydrationskipHydrationSame
version-Server handles versioning
migrate-Handle before vault()
OptionDescription
recoveryKeyRequired. Encryption key.
serverOptional. Server URL for sync.
getTokenRequired if server set.
syncIntervalAuto-sync interval (default 30s).
// persist()
useStore.persist.hasHydrated()
useStore.persist.rehydrate()
// vault()
useStore.vault.hasHydrated()
useStore.vault.rehydrate()
useStore.vault.sync() // Bidirectional sync
useStore.vault.push() // Push to server
useStore.vault.pull() // Pull from server
useStore.vault.getSyncStatus() // Sync status
useStore.vault.hasPendingChanges() // Offline queue

When switching, existing unencrypted data won’t be readable.

Just switch. Users start with empty state.

// One-time migration
const oldData = localStorage.getItem("my-store");
if (oldData) {
const parsed = JSON.parse(oldData);
// Set state in new store
useStore.setState(parsed.state);
// Remove old data
localStorage.removeItem("my-store");
}
// Keep both temporarily
const useLegacy = create(persist(...));
const useStore = create(vault(...));
// Migrate on first load
if (useLegacy.getState().data && !useStore.vault.hasHydrated()) {
useStore.setState(useLegacy.getState());
useLegacy.persist.clearStorage();
}

Types work the same:

// Before
import type { PersistOptions } from "zustand/middleware";
// After
import type { VaultOptions } from "@zod-vault/zustand";

Expected when switching. Old unencrypted data can’t be decrypted. Use migration strategy above.

Same as persist():

vault(config, {
name: "my-store",
recoveryKey: "...",
skipHydration: true,
});
// Client-side
useStore.vault.rehydrate();