butr
Guides

Custom storage driver

Back persistence with cookies, memory, or React Native AsyncStorage.

butr persists through a StorageDriver — a three-method get/set/remove interface that may be async. Wrap a driver in WalletStorage and pass it as storage.

type StorageDriver = {
  getItem(key: string): MaybePromise<string | null>;
  setItem(key: string, value: string): MaybePromise<void>;
  removeItem(key: string): MaybePromise<void>;
};

Built-in drivers

import {
  createBrowserStorageDriver, // localStorage (the default)
  createCookieStorageDriver, // cookies — domain/path/SameSite/secure
  createMemoryStorageDriver, // in-memory, no persistence
  WalletStorage,
} from "@usebutr/core";

const storage = new WalletStorage({
  keyPrefix: "myapp",
  persistent: createCookieStorageDriver({
    domain: "example.com",
    maxAgeSec: 604_800,
    path: "/",
    sameSite: "Lax",
    secure: true,
  }),
  session: createMemoryStorageDriver(),
});

React Native / Expo (AsyncStorage)

The driver is async-friendly, so any AsyncStorage-like API works. This is the exact demo-expo-web driver:

async-storage-driver.ts
import AsyncStorage from "@react-native-async-storage/async-storage";
import type { StorageDriver } from "@usebutr/core";

const asyncStorageDriver: StorageDriver = {
  getItem: (key) => AsyncStorage.getItem(key),
  setItem: (key, value) => AsyncStorage.setItem(key, value),
  removeItem: (key) => AsyncStorage.removeItem(key),
};

export { asyncStorageDriver };

Wire it into WalletManagerProvider:

wallet-provider.tsx
import type { ReactNode } from "react";
import { WalletStorage } from "@usebutr/core";
import { WalletManagerProvider } from "@usebutr/react";
import { autoDiscovery } from "@usebutr/wallets";
import { asyncStorageDriver } from "./async-storage-driver";

const KEY_PREFIX = "butr-demo";

const discovery = autoDiscovery();

const storage = new WalletStorage({
  keyPrefix: KEY_PREFIX,
  persistent: asyncStorageDriver,
  session: asyncStorageDriver,
});

const WalletProvider = ({ children }: { children: ReactNode }) => (
  <WalletManagerProvider discovery={discovery} storage={storage} storageKeyPrefix={KEY_PREFIX}>
    {children}
  </WalletManagerProvider>
);

AsyncStorage has no true session-storage equivalent. The demo backs both drivers with the same store and accepts that session entries outlive the session — harmless here, since butr's session storage only holds the active-connector id, which is overwritten on the next connect. If you need strict session semantics, namespace session keys and sweep them on startup.

Source: apps/demo-expo-web/src/async-storage-driver.ts and apps/demo-expo-web/src/wallet-provider.tsx in the butr repository. See also persistence concepts.

On this page