Skip to main content
Version: 0.14 (unstable)

Setting up the React SDK

Install

The React SDK has a hard peer dependency on @miden-sdk/miden-sdk — install both:

npm install @miden-sdk/react @miden-sdk/miden-sdk
# or
yarn add @miden-sdk/react @miden-sdk/miden-sdk
# or
pnpm add @miden-sdk/react @miden-sdk/miden-sdk

React 18 or newer is required.

Wrap your app in MidenProvider

MidenProvider loads the Web SDK's WebAssembly module, spins up the dedicated worker, wires the keystore, and kicks off the auto-sync loop. Put it at the root of your React tree — typically in App.tsx or your Next.js root layout.

import { MidenProvider } from "@miden-sdk/react";

function App() {
return (
<MidenProvider config={{ rpcUrl: "testnet" }}>
<YourApp />
</MidenProvider>
);
}

Every hook in the rest of this section assumes a MidenProvider is mounted somewhere above it.

Configuration

<MidenProvider
config={{
rpcUrl: "testnet", // "devnet" | "testnet" | "localhost" | custom URL
prover: "testnet", // "local" | "devnet" | "testnet" | custom URL
autoSyncInterval: 15_000, // ms; set to 0 to disable auto-sync
noteTransportUrl: "testnet", // optional; required for private notes
}}
loadingComponent={<Loading />} // rendered while WASM boots
errorComponent={<Error />} // rendered if init fails
>
<YourApp />
</MidenProvider>

MidenConfig fields

FieldTypeDescription
rpcUrl"devnet" | "testnet" | "localhost" | stringNode RPC endpoint. Shorthands expand to hosted Miden endpoints; any other string is treated as a raw URL.
prover"local" | "devnet" | "testnet" | string | ProverConfigDefault prover. "local" runs in-browser. ProverConfig supports a primary + fallback pair if you want automatic fallback.
autoSyncIntervalnumberMilliseconds between automatic sync pulls. 0 disables the loop (you can still call sync() manually). Default: 15000.
noteTransportUrl"devnet" | "testnet" | stringNote transport service. Required for sendPrivate / fetchPrivate.
proverTimeoutMsnumberPer-transaction prover timeout.
seedUint8Array32-byte RNG seed for deterministic account-ID derivation in tests.

Network shorthands

ShorthandMeaning
devnetDevelopment / pre-production testing, fake tokens
testnetPre-production testing against the hosted Miden testnet
localhostLocal node at http://localhost:57291

loadingComponent and errorComponent

  • loadingComponent is rendered during the brief WASM load phase (first render only).
  • errorComponent is rendered if initialization fails. It accepts either a ReactNode or (error: Error) => ReactNode.

Both are optional. Leaving them unset uses sensible defaults.

Client lifecycle

useMiden() is the raw context hook. Most apps never need it — the specialized hooks are easier — but it's there when you want to reach into lifecycle state directly.

import { useMiden } from "@miden-sdk/react";

function Status() {
const { isReady, isInitializing, error, sync, runExclusive } = useMiden();

if (isInitializing) return <p>Loading Miden…</p>;
if (error) return <p>Init error: {error.message}</p>;

return <button onClick={() => sync()}>Sync</button>;
}
  • isReadytrue once the WASM module, keystore, and signer are fully initialised.
  • isInitializingtrue during the first load.
  • error — non-null if init failed.
  • sync() — trigger a manual sync pass outside the auto-sync loop.
  • runExclusive<T>(fn: () => Promise<T>): Promise<T> — serialize a block of async work under the internal lock. fn takes no arguments; reach for the client via useMidenClient() if you need one inside. See race conditions.

useMidenClient() is a shortcut that returns the ready WebClient directly, throwing if the provider isn't ready yet:

import { useMidenClient } from "@miden-sdk/react";

function AdvancedCall() {
const client = useMidenClient();
const header = await client.getBlockHeaderByNumber(100);
// ...
}

Use it for APIs the React SDK hooks don't expose.

Hook result conventions

Each hook exports its own result interface — UseSendResult, AccountsResult, NotesResult, and so on — rather than a generic QueryResult<T> wrapper. Data lives in named fields (e.g. accounts, wallets, faucets) not inside a common data key. The shared machinery is narrower than that:

Query hooks

Every query hook exposes at least:

{
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}

Plus the hook-specific data fields. For example:

const { wallets, faucets, isLoading, error, refetch } = useAccounts();

if (isLoading) return <Spinner />;
if (error) return <p>{error.message}</p>;
return <AccountList wallets={wallets} faucets={faucets} />;

Mutation hooks

Every mutation hook exposes:

{
// Domain-specific action function — `send` for useSend, `mint` for useMint, etc.
[action]: (options) => Promise<Result>;
result: Result | null;
isLoading: boolean;
stage: TransactionStage;
error: Error | null;
reset: () => void;
}

The action function name mirrors the hook: useSend returns send, useMint returns mint, useConsume returns consume. That keeps call sites readable without destructured renames.

Transaction-producing mutations progress through the TransactionStage states:

type TransactionStage =
| "idle"
| "executing"
| "proving"
| "submitting"
| "complete";

Pattern:

const { send, stage, isLoading, error } = useSend();

return (
<button
onClick={() => send({ from, to, assetId, amount: 100n })}
disabled={isLoading}
>
{isLoading ? `${stage}` : "Send"}
</button>
);

See Mutation hooks for the full surface.

Account ID formats

Every hook accepts either form:

useAccount("0x1234567890abcdef");   // hex
useAccount("mtst1qy35..."); // bech32 (testnet prefix)

// Convert for display
account.bech32id(); // "mtst1qy35..." on testnet

The SDK normalises internally — you don't need to convert yourself. Bech32 prefixes encode the network: mtst1… on testnet, mdev1… on devnet. The prefix is derived from the rpcUrl you configured on MidenProvider.

Next

  • Query hooks — read account, note, sync, and metadata state.
  • Mutation hooks — create wallets, send, mint, consume, swap.
  • Advanced — custom scripts, session wallets, import/export.
  • Signers — integrate Para, Turnkey, MidenFi, or a custom wallet.