@solana/client keeps the runtime surface lean. One store, one RPC stack, and a wallet registry power
the different helpers so the same instance can back CLIs, scripts, or full UIs. Actions, watchers, and
helpers all share cache, subscriptions, and wallet sessions through that single client.
When you are building a purely React experience it is usually faster to start with
@solana/react-hooks. The hooks package wraps this same client runtime and
exposes ready-made hooks so you only drop to the headless client when you need extra control.
Install
$npm install @solana/client
Use any package manager; the client runs in browsers, workers, React, Svelte, or server-side runtimes.
Create a client once
Choose Wallet Standard connectors (auto discovery is the fastest way to start), then create the client. This single object exposes the store, actions, watchers, and helpers.
import { autoDiscover, createClient } from "@solana/client";const client = createClient({endpoint: "https://api.devnet.solana.com",websocketEndpoint: "wss://api.devnet.solana.com",walletConnectors: autoDiscover(),});await client.actions.connectWallet("wallet-standard:phantom");const balance = await client.actions.fetchBalance("Fke...address");console.log(balance.lamports?.toString());
The client store tracks cluster config, subscriptions, pending transactions, and wallet sessions. You can provide your own Zustand store if you need persistence or multi-tab coordination.
Wallet orchestration
Connectors encapsulate Wallet Standard metadata plus connect/disconnect logic. Register the built-in
phantom(), solflare(), backpack(), or autoDiscover() helpers, or wrap custom providers with
createWalletStandardConnector. All wallet actions (connect, disconnect, sign, send) flow through the
client registry so every consumer stays in sync.
Actions, watchers, and helpers
- Actions wrap common RPC reads and writes while updating the store (e.g.,
fetchAccount,requestAirdrop,setCluster). - Watchers multiplex websocket subscriptions, stream updates into the store, and give you abort handles for cleanup.
- Helpers expose higher-level flows such as SOL transfers, SPL token helpers, signature polling, and transaction pools.
const abortWatcher = client.watchers.watchBalance({ address: "Fke...address" },(lamports) => {console.log("live balance", lamports.toString());},);// Later when the component unmounts or the flow endsabortWatcher.abort();
Transaction helper pattern
The transaction helper owns blockhash refresh, fee payer resolution, and signing. You can prepare, inspect, and send with whatever UX you prefer.
const prepared = await client.helpers.transaction.prepare({authority: client.store.getState().wallet.session!,instructions: [instructionA, instructionB],});await client.helpers.transaction.simulate(prepared, { commitment: "processed" });const signature = await client.helpers.transaction.send(prepared);console.log("submitted", signature.toString());
Use prepareAndSend for a pre-built flow (simulation plus logging) or call sign / toWire to collect
signatures manually before relaying the wire format yourself.
Common patterns for Solana devs
- Headless state machines: Run the client inside API routes, scripts, or workers to reuse the same wallet + RPC orchestration logic that powers your UI.
- Realtime dashboards: Combine watchers (balances, accounts, signatures) with your preferred UI library; the client handles websocket fan-out and cache invalidation.
- Custom stores: Inject your own Zustand store to hydrate from IndexedDB/localStorage, mirror state to server sessions, or coordinate between browser tabs.
- Bridge to React hooks: Pass a configured client instance to
@solana/react-hookswhen you want ergonomic hooks on top of the same runtime. - Testability: The single client interface can be mocked in unit tests, making it easy to simulate RPC responses or wallet sessions without a browser wallet present.
Is this page helpful?