Local

Use SDK 4.0.0 LocalKVStore to read, save and remove encrypted wallet-backed values; understand fees, recovery, privacy and cross-device conflict limits.

Read as Markdown

Store small, wallet-owned application values with LocalKVStore, exported directly from @bsv/sdk. This guide was checked against SDK 4.0.0 on October 26, 2026. Use a maintained, patched Node.js 22 or 24 release and install npm install @bsv/sdk@4.0.0.

What local means

This is not browser localStorage. Values are represented by PushDrop transaction outputs tracked in a wallet basket. The context names that basket, and the connected wallet supplies permissions, signing, encryption and its storage/recovery path. The same wallet account and restored wallet data are needed on another device; the browser's old cache is not the source of truth.

This is also not a public shared database or a distributed locking service. Use it for small preferences, drafts or user-owned app records. Public multi-user discovery belongs in an overlay, with the appropriate application protocol.

A complete typed example

The SDK exports the class without an internal-file import or an as any workaround. The constructor arguments below are wallet, context, value encryption, optional originator and delayed-broadcast policy. Keep the normal requesting origin; do not impersonate another origin to bypass permission decisions.

1import { LocalKVStore, WalletClient } from '@bsv/sdk'
2
3const wallet = new WalletClient('auto')
4const preferences = new LocalKVStore(
5  wallet,
6  'example app preferences',
7  true,      // encrypt values
8  undefined, // use the normal app origin
9  false      // request immediate broadcast for writes
10)
11
12async function readTheme() {
13  await wallet.waitForAuthentication()
14  return preferences.get('theme', 'system')
15}
16
17async function saveTheme(theme: 'light' | 'dark' | 'system') {
18  await wallet.waitForAuthentication()
19  const outpoint = await preferences.set('theme', theme)
20  if (await preferences.get('theme') !== theme) {
21    throw new Error('The saved preference could not be read back')
22  }
23  return outpoint
24}
25
26async function removeTheme() {
27  await wallet.waitForAuthentication()
28  return preferences.remove('theme')
29}
30
31// These helpers are not called automatically. Saving/removing requests wallet actions.
Copied!

The first successful read returns the stored value or 'system' when the key is absent. set returns an outpoint in txid.vout form; remove returns transaction IDs and returns an empty array when there is nothing to remove. Read back an important record before acknowledging to your user that it is safely stored.

A new value creates a 1-satoshi output plus network fees. Updating normally spends the previous output(s) into a replacement; removing spends existing output(s) without replacing the value. These are real wallet actions and can require funding and approval. The output amount is not a fixed total price. In 4.0.0, setting an already stored identical value can reuse its existing outpoint without another transaction.

Encryption is on by default, but on-chain transaction existence, amounts and timing remain observable. Do not place recovery secrets in examples, context names or keys. Disabling encryption deliberately publishes plaintext values. Removing a key does not erase historical blockchain bytes, backups or other retained copies.

Concurrency and conflicting state

The SDK queues operations for a key within that LocalKVStore instance. This does not provide a distributed lock between tabs, separate instances or devices. A get, increment and set sequence is not an atomic distributed counter. Coordinate writes in your application, or use independent immutable record keys and an explicit merge protocol when concurrent-device history must be preserved.

get can report ambiguous or invalid output state. Treat that as an error, not an empty value. Although a deliberate set can collapse multiple valid outputs, it is a mutation and can overwrite meaning; do not automatically reset or relinquish recovery outputs to make an error disappear. Preserve the original error and records, check the wallet/profile, context and data restoration, then resolve the conflict deliberately.

Recovery and uncertain outcomes

Keep the context, key scheme, encryption policy and derivation assumptions stable across app releases. Back up and restore the wallet account and its supported data/storage service. A private key or browser bookmark alone is not a promise that all tracked outputs and proof data are present.

A timeout does not prove a write was never created. Inspect wallet action history and read the key before submitting another mutation. Allowing delayed broadcast is a separate application choice; it does not make persistence, confirmation or cross-device availability immediate. Errors must remain visible instead of silently becoming default values.

Mountaintops uses this wallet-backed pattern for address metadata, with its own recovery and merge rules. Its funding/recovery guide explains the user-facing boundaries; do not assume a generic key-value example implements those rules for you.

See the maintained LocalKVStore source and wallet API before extending the example.

Was this page helpful?