# Framework Kit - Complete Documentation
> Developer tools for Solana built on Solana Kit
---
# Framework Kit
URL: https://framework-kit.dev/docs
> Developer tools for Solana built on Solana Kit
A family of libraries for building production-ready Solana apps. Use the universal client in any JavaScript runtime, add React hooks for reactive UIs, or migrate existing web3.js code incrementally.
## Packages
| Package | Description |
| --- | --- |
| [@solana/client](/docs/client) | Framework-agnostic client for wallets, RPC, and transactions. Works in React, Svelte, Vue, Node.js, Bun, workers, or any JavaScript runtime. |
| [@solana/react-hooks](/docs/react-hooks) | React hooks and provider built on the client. Reactive state for balances, wallets, and transactions. |
| [@solana/web3-compat](/docs/web3-compat) | Compatibility layer for migrating from `@solana/web3.js`. Keep using familiar APIs while adopting Solana Kit under the hood. |
## Why Framework Kit?
Building Solana apps usually means wiring together RPC connections, wallet adapters, and state management yourself. Framework Kit handles this for you:
- **Universal client** - One client that works everywhere: browsers, servers, edge functions, workers
- **Wallet Standard support** - Auto-discover installed wallets with a unified connection API
- **Real-time subscriptions** - Watch balances, accounts, and signatures with WebSocket subscriptions
- **Token operations** - Built-in helpers for SOL transfers and SPL token operations
- **TypeScript-first** - Full type inference and autocomplete out of the box
- **Incremental adoption** - Start with web3-compat, migrate to client, add React hooks when ready
## Quick Start
### Using the Client (Any Framework)
The client works in any JavaScript environment:
```ts
import { autoDiscover, createClient } from "@solana/client";
const client = createClient({
cluster: "devnet",
walletConnectors: autoDiscover(),
});
// Connect a wallet
const connectors = client.connectors.all;
await client.actions.connectWallet(connectors[0].id);
// Fetch balance
const wallet = client.store.getState().wallet;
if (wallet.status === "connected") {
const balance = await client.actions.fetchBalance(wallet.session.account.address);
console.log(`Balance: ${balance.toString()} lamports`);
}
// Send SOL
const signature = await client.solTransfer.sendTransfer({
amount: 100_000_000n, // 0.1 SOL
authority: wallet.session,
destination: "Fg6PaFpoGXkYsidMpWFKfwtz6DhFVyG4dL1x8kj7ZJup",
});
```
### Using React Hooks
For React apps, wrap once with the provider and use hooks anywhere:
```tsx
import { autoDiscover, createClient } from "@solana/client";
import { SolanaProvider, useWalletConnection, useBalance } from "@solana/react-hooks";
const client = createClient({
cluster: "devnet",
walletConnectors: autoDiscover(),
});
function WalletPanel() {
const { connectors, connect, disconnect, wallet, status } = useWalletConnection();
const { lamports } = useBalance(wallet?.account.address);
if (status === "connected") {
return (
{wallet.account.address.toString()}
Balance: {lamports?.toString() ?? "..."} lamports
);
}
return connectors.map((c) => (
));
}
export function App() {
return (
);
}
```
### Migrating from web3.js
If you have existing code using `@solana/web3.js`, swap imports to start migrating:
```diff
- import { Connection, PublicKey } from "@solana/web3.js";
+ import { Connection, PublicKey } from "@solana/web3-compat";
const connection = new Connection("https://api.devnet.solana.com");
const balance = await connection.getBalance(publicKey);
```
## Next Steps
- [Getting Started](/docs/getting-started) - Install and configure your first project
- [Client API](/docs/client) - Core library for any JavaScript runtime
- [React Hooks](/docs/react-hooks) - Reactive hooks for React apps
- [Migration Guide](/docs/web3-compat) - Migrate from @solana/web3.js
---
# API Reference
URL: https://framework-kit.dev/docs/api-reference
> Complete API reference for Framework Kit packages
Quick reference for all exports. Full API docs are auto-generated from TypeScript source via [TypeDoc](https://typedoc.org/).
## @solana/client
The core client library exports the following:
### Client Creation
| Export | Description |
| --- | --- |
| `createClient(config)` | Create a new Solana client instance |
| `resolveCluster(config)` | Resolve cluster endpoints from moniker or custom URLs |
### Wallet Connectors
| Export | Description |
| --- | --- |
| `autoDiscover(options?)` | Auto-discover installed wallet extensions |
| `filterByNames(...names)` | Filter wallets by name |
| `phantom()` | Phantom wallet connector |
| `solflare()` | Solflare wallet connector |
| `backpack()` | Backpack wallet connector |
| `metamask()` | MetaMask Snaps connector |
| `injected(wallet)` | Generic injected wallet connector |
### Address Utilities
| Export | Description |
| --- | --- |
| `toAddress(input)` | Convert string or PublicKey to Address |
| `isAddress(value)` | Check if value is a valid Address |
### Numeric Utilities
| Export | Description |
| --- | --- |
| `LAMPORTS_PER_SOL` | Lamports per SOL constant (1_000_000_000n) |
| `lamports(value)` | Create a Lamports value |
| `lamportsFromSol(sol)` | Convert SOL to lamports |
| `lamportsToSolString(lamports)` | Convert lamports to SOL string |
| `createTokenAmount(decimals)` | Create token amount math utilities |
### State Serialization
| Export | Description |
| --- | --- |
| `serializeSolanaState(state)` | Serialize client state for storage |
| `deserializeSolanaState(data)` | Deserialize stored state |
| `applySerializableState(store, state)` | Apply serialized state to store |
### Types
Key TypeScript types exported from the package:
```ts
// Client configuration
type SolanaClientConfig = {
cluster?: ClusterMoniker;
endpoint?: string;
websocketEndpoint?: string;
walletConnectors?: WalletConnectorFn[];
};
// Wallet state
type WalletState =
| { status: "disconnected" }
| { status: "connecting"; connectorId: string }
| { status: "connected"; session: WalletSession; connectorId: string };
// Wallet session (for signing)
type WalletSession = {
account: WalletAccount;
signTransaction: (tx: Transaction) => Promise;
signMessage: (message: Uint8Array) => Promise;
};
// Cluster configuration
type ClusterMoniker = "mainnet" | "mainnet-beta" | "testnet" | "devnet" | "localnet" | "localhost";
// Transaction input
type TransactionInstructionInput = {
programAddress: Address;
accounts: AccountMeta[];
data: Uint8Array;
};
```
## @solana/react-hooks
### Provider
| Export | Description |
| --- | --- |
| `SolanaProvider` | Root provider component |
| `SolanaQueryProvider` | Provider for query hooks with Suspense support |
### Wallet Hooks
| Hook | Description |
| --- | --- |
| `useWalletConnection()` | Complete wallet connection management |
| `useWallet()` | Access wallet state |
| `useWalletSession()` | Get current session for signing |
| `useWalletActions()` | Connect/disconnect actions |
| `useWalletModalState()` | Modal visibility management |
| `useConnectWallet()` | Connect action only |
| `useDisconnectWallet()` | Disconnect action only |
### Data Hooks
| Hook | Description |
| --- | --- |
| `useBalance(address)` | Fetch and watch balance |
| `useAccount(address)` | Fetch and watch account |
| `useLookupTable(address)` | Fetch lookup table |
| `useNonceAccount(address)` | Fetch nonce account |
| `useProgramAccounts(program)` | Query program accounts |
### Transaction Hooks
| Hook | Description |
| --- | --- |
| `useSolTransfer()` | Send SOL |
| `useSplToken(mint)` | SPL token operations |
| `useWrapSol()` | Wrap/unwrap SOL |
| `useSendTransaction()` | Simple transaction send |
| `useTransactionPool()` | Complex transaction building |
| `useSimulateTransaction(wire)` | Simulate transactions |
### Status Hooks
| Hook | Description |
| --- | --- |
| `useSignatureStatus(signature)` | Watch signature status |
| `useWaitForSignature(signature)` | Wait for confirmation |
| `useClusterState()` | Current cluster info |
| `useClusterStatus()` | Cluster connection status |
| `useLatestBlockhash()` | Get latest blockhash |
### Utility Hooks
| Hook | Description |
| --- | --- |
| `useClientStore(selector)` | Access Zustand store |
| `useSolanaClient()` | Access client instance |
## @solana/web3-compat
### Re-exports
| Export | Description |
| --- | --- |
| `Keypair` | Key pair for signing |
| `PublicKey` | Public key representation |
| `Transaction` | Legacy transaction |
| `TransactionInstruction` | Transaction instruction |
| `VersionedTransaction` | Versioned transaction |
| `LAMPORTS_PER_SOL` | Lamports per SOL constant |
### Bridge Functions
| Function | Description |
| --- | --- |
| `toAddress(publicKey)` | Convert PublicKey to Kit Address |
| `toPublicKey(address)` | Convert Kit Address to PublicKey |
| `fromWeb3Instruction(ix)` | Convert web3.js instruction to Kit |
| `toWeb3Instruction(ix)` | Convert Kit instruction to web3.js |
| `toKitSigner(keypair)` | Convert Keypair to Kit signer |
### Classes
| Class | Description |
| --- | --- |
| `Connection` | web3.js-compatible RPC connection |
| `SystemProgram` | System program instructions |
### Utilities
| Function | Description |
| --- | --- |
| `sendAndConfirmTransaction` | Send and confirm a transaction |
| `compileFromCompat` | Compile web3.js tx to Kit format |
## Generated Documentation
Full API documentation is generated from source code and available as build artifacts:
- **@solana/client**: Generated via `pnpm --filter @solana/client docs`
- **JSON format**: Generated via `pnpm --filter @solana/client docs:json`
The CI automatically generates and uploads API documentation on every push to main that changes the client source code.
### Building Locally
To generate API docs locally:
```bash
# Generate markdown docs
pnpm --filter @solana/client docs
# Generate JSON API spec
pnpm --filter @solana/client docs:json
```
Output is written to `packages/client/docs/`.
---
# @solana/client
URL: https://framework-kit.dev/docs/client
> Framework-agnostic client for RPC, wallets, and transactions
Framework-agnostic building blocks for Solana. Works in any runtime: React, Svelte, Vue, Node.js, Bun, Deno, Cloudflare Workers, or plain browser scripts.
## Installation
```bash
npm install @solana/client
```
```bash
pnpm add @solana/client
```
```bash
yarn add @solana/client
```
```bash
bun add @solana/client
```
## Creating a Client
```ts
import { autoDiscover, createClient } from "@solana/client";
const client = createClient({
endpoint: "https://api.devnet.solana.com",
websocketEndpoint: "wss://api.devnet.solana.com",
walletConnectors: autoDiscover(),
});
```
## Wallet Connection
### Connect and Disconnect
```ts
// Get available connectors
const connectors = client.connectors.all;
// Connect to a wallet
await client.actions.connectWallet(connectors[0].id);
// Check wallet state
const wallet = client.store.getState().wallet;
if (wallet.status === "connected") {
console.log(wallet.session.account.address.toString());
}
// Disconnect
await client.actions.disconnectWallet();
```
### Connector IDs
Connectors use **canonical IDs**:
- Wallet Standard: `wallet-standard:` (example: `wallet-standard:phantom`)
- Mobile Wallet Adapter: `mwa:`
- WalletConnect: `walletconnect`
For convenience, calls like `connectWallet("phantom")` also work (fallback-only: prefers `wallet-standard:phantom`, then `mwa:phantom`). The client persists the **canonical** ID in state for more reliable restore/auto-connect.
### Wallet Connectors
Framework Kit uses the Wallet Standard for wallet discovery:
```ts
import { autoDiscover, filterByNames } from "@solana/client";
// Auto-discover all installed wallets
const connectors = autoDiscover();
// Filter to specific wallets
const filteredConnectors = autoDiscover({
filter: filterByNames("phantom", "solflare"),
});
// Custom filter function
const customConnectors = autoDiscover({
filter: (wallet) => wallet.name.toLowerCase().includes("phantom"),
});
```
Built-in wallet connectors for explicit control:
```ts
import { phantom, solflare, backpack, metamask, injected } from "@solana/client";
const client = createClient({
cluster: "devnet",
walletConnectors: [phantom(), solflare(), backpack()],
});
```
## ConnectorKit (optional)
ConnectorKit integration is exposed as a **stable, opt-in entrypoint**:
```ts
import { connectorKit } from "@solana/client/connectorkit";
import { createClient } from "@solana/client";
const walletConnectors = connectorKit({
// Pass a ConnectorKit client/config/defaultConfig (see ConnectorKit docs).
defaultConfig: { /* ... */ },
});
const client = createClient({
cluster: "devnet",
walletConnectors,
});
```
`@solana/connector` is an **optional peer dependency** of `@solana/client`. Install it to use `@solana/client/connectorkit`.
## Fetching Data
### Account Data
```ts
import { toAddress } from "@solana/client";
const address = toAddress("Fg6PaFpoGXkYsidMpWFKfwtz6DhFVyG4dL1x8kj7ZJup");
// Fetch account
const account = await client.actions.fetchAccount(address);
console.log(account.lamports?.toString());
```
### Balance
```ts
const lamports = await client.actions.fetchBalance(address);
console.log(`Lamports: ${lamports.toString()}`);
```
### Address Lookup Tables
```ts
// Single lookup table
const lut = await client.actions.fetchLookupTable(lutAddress);
console.log(`Addresses in LUT: ${lut.addresses.length}`);
// Multiple lookup tables
const luts = await client.actions.fetchLookupTables([lutAddress1, lutAddress2]);
```
### Nonce Accounts
```ts
const nonce = await client.actions.fetchNonceAccount(nonceAddress);
console.log(`Nonce: ${nonce.blockhash}`);
console.log(`Authority: ${nonce.authority}`);
```
## Watchers
Subscribe to real-time updates:
### Watch Balance
```ts
const watcher = client.watchers.watchBalance({ address }, (nextLamports) => {
console.log("Updated balance:", nextLamports.toString());
});
// Clean up when done
watcher.abort();
```
### Watch Account
```ts
const watcher = client.watchers.watchAccount({ address }, (account) => {
console.log("Account updated:", account);
});
watcher.abort();
```
### Watch Signature
```ts
const watcher = client.watchers.watchSignature(
{ signature, commitment: "confirmed" },
(notification) => console.log("Signature update:", notification),
);
watcher.abort();
```
## Transfers
### SOL Transfer
```ts
const wallet = client.store.getState().wallet;
if (wallet.status !== "connected") throw new Error("Connect wallet first");
const signature = await client.solTransfer.sendTransfer({
amount: 100_000_000n, // 0.1 SOL
authority: wallet.session,
destination: "Ff34MXWdgNsEJ1kJFj9cXmrEe7y2P93b95mGu5CJjBQJ",
});
console.log(signature.toString());
```
### SPL Token Transfer
```ts
const usdc = client.splToken({ mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" });
// Fetch balance
const balance = await usdc.fetchBalance(wallet.session.account.address);
console.log(`Balance: ${balance.uiAmount}`);
// Transfer
const signature = await usdc.sendTransfer({
amount: 1n,
authority: wallet.session,
destinationOwner: "Ff34MXWdgNsEJ1kJFj9cXmrEe7y2P93b95mGu5CJjBQJ",
});
```
### Token 2022 Support
The SPL token helper supports Token 2022 (Token Extensions) mints. Use the `tokenProgram` option to specify the program:
```ts
// Auto-detect program (recommended for existing mints)
const token2022 = client.splToken({
mint: "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", // PYUSD
tokenProgram: "auto",
});
// Fetch balance works the same way
const balance = await token2022.fetchBalance(wallet.session.account.address);
// Transfer works the same way
const signature = await token2022.sendTransfer({
amount: 10,
authority: wallet.session,
destinationOwner: recipientAddress,
});
```
You can also explicitly specify the Token 2022 program address:
```ts
import { TOKEN_2022_PROGRAM_ADDRESS } from "@solana/client";
const token = client.splToken({
mint: mintAddress,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
});
```
The `detectTokenProgram` utility is also available for manual program detection:
```ts
import { detectTokenProgram } from "@solana/client";
const result = await detectTokenProgram(client.runtime, mintAddress);
console.log(result.programId); // 'token' or 'token-2022'
```
## Custom Transactions
Build and send arbitrary transactions:
```ts
import { getTransferSolInstruction } from "@solana-program/system";
const wallet = client.store.getState().wallet;
if (wallet.status !== "connected") throw new Error("Connect wallet first");
// Prepare transaction
const prepared = await client.transaction.prepare({
authority: wallet.session,
instructions: [
getTransferSolInstruction({
destination: "Ff34MXWdgNsEJ1kJFj9cXmrEe7y2P93b95mGu5CJjBQJ",
lamports: 10_000n,
source: wallet.session.account.address,
}),
],
version: "auto", // 'legacy' | 0 | 'auto'
});
// Serialize for inspection
const wire = await client.transaction.toWire(prepared);
// Send
const signature = await client.transaction.send(prepared);
console.log(signature.toString());
```
## Airdrop (Devnet/Testnet)
```ts
const signature = await client.actions.requestAirdrop(address, 1_000_000_000n); // 1 SOL
console.log(signature.toString());
```
## Cluster Configuration
### Using Monikers
```ts
const client = createClient({
cluster: "mainnet", // 'devnet' | 'testnet' | 'localnet' | 'localhost'
walletConnectors: autoDiscover(),
});
```
### Custom Endpoints
```ts
const client = createClient({
endpoint: "http://127.0.0.1:8899",
// WebSocket inferred as ws://127.0.0.1:8900
});
```
### Resolve Cluster Manually
```ts
import { resolveCluster } from "@solana/client";
const resolved = resolveCluster({ moniker: "testnet" });
console.log(resolved.endpoint, resolved.websocketEndpoint);
```
## Numeric Utilities
### Lamports
```ts
import {
LAMPORTS_PER_SOL,
lamports,
lamportsFromSol,
lamportsToSolString,
} from "@solana/client";
const amount = lamportsFromSol(1.5); // 1_500_000_000n
const sol = lamportsToSolString(amount); // "1.5"
```
### Token Amounts
```ts
import { createTokenAmount } from "@solana/client";
const tokenMath = createTokenAmount(6); // USDC has 6 decimals
const parsed = tokenMath.parse("10.5"); // 10_500_000n
const formatted = tokenMath.format(10_500_000n); // "10.5"
```
## Serialization
Save and restore client state:
```ts
import {
serializeSolanaState,
deserializeSolanaState,
applySerializableState,
} from "@solana/client";
// Serialize current state
const state = client.store.getState();
const serialized = serializeSolanaState(state);
localStorage.setItem("solana-state", JSON.stringify(serialized));
// Restore state
const stored = JSON.parse(localStorage.getItem("solana-state"));
const deserialized = deserializeSolanaState(stored);
applySerializableState(client.store, deserialized);
```
## Store Access
The client uses Zustand for state management:
```ts
// Get current state
const state = client.store.getState();
// Subscribe to changes
const unsubscribe = client.store.subscribe((state) => {
console.log("State changed:", state);
});
```
## API Reference
### Client Actions
| Action | Description |
| --- | --- |
| `connectWallet(id)` | Connect to a wallet by connector ID |
| `disconnectWallet()` | Disconnect the current wallet |
| `fetchAccount(address)` | Fetch account data |
| `fetchBalance(address)` | Fetch lamport balance |
| `fetchLookupTable(address)` | Fetch address lookup table |
| `fetchLookupTables(addresses)` | Fetch multiple lookup tables |
| `fetchNonceAccount(address)` | Fetch nonce account data |
| `requestAirdrop(address, lamports)` | Request devnet/testnet airdrop |
| `sendTransaction(tx)` | Send a signed transaction |
| `setCluster(config)` | Change cluster/endpoint |
### Client Helpers
| Helper | Description |
| --- | --- |
| `client.solTransfer` | SOL transfer operations |
| `client.splToken({ mint })` | SPL token operations |
| `client.transaction` | Transaction building and sending |
### Client Watchers
| Watcher | Description |
| --- | --- |
| `watchAccount({ address }, callback)` | Subscribe to account changes |
| `watchBalance({ address }, callback)` | Subscribe to balance changes |
| `watchSignature({ signature }, callback)` | Subscribe to signature status |
---
# Getting Started
URL: https://framework-kit.dev/docs/getting-started
> Install and configure Framework Kit in under 5 minutes
Pick the packages you need and start building.
| Use Case | Install |
| --- | --- |
| Any JS runtime (Node, Bun, Deno, browser, workers) | [`@solana/client`](/docs/client) |
| React applications | [`@solana/client`](/docs/client) [`@solana/react-hooks`](/docs/react-hooks) |
| Migrating from @solana/web3.js | [`@solana/web3-compat`](/docs/web3-compat) |
## Installation
### Client Only (Any Runtime)
```bash
npm install @solana/client
```
```bash
pnpm add @solana/client
```
```bash
yarn add @solana/client
```
```bash
bun add @solana/client
```
### With React Hooks
```bash
npm install @solana/client @solana/react-hooks
```
```bash
pnpm add @solana/client @solana/react-hooks
```
```bash
yarn add @solana/client @solana/react-hooks
```
```bash
bun add @solana/client @solana/react-hooks
```
### Migration Package
```bash
npm install @solana/web3-compat
```
```bash
pnpm add @solana/web3-compat
```
```bash
yarn add @solana/web3-compat
```
```bash
bun add @solana/web3-compat
```
## Requirements
- Node.js 20.18.0+, Bun 1.0+, or Deno 1.40+
- TypeScript 5.3.3+ (recommended)
- React 18+ (only if using `@solana/react-hooks`)
## Basic Setup
### Using the Client (Any Framework)
The client works standalone in any JavaScript environment:
```ts
import { autoDiscover, createClient } from "@solana/client";
const client = createClient({
cluster: "devnet",
walletConnectors: autoDiscover(), // Finds installed wallet extensions
});
// Connect to a wallet
const connectors = client.connectors.all;
await client.actions.connectWallet(connectors[0].id);
// Access wallet state
const wallet = client.store.getState().wallet;
if (wallet.status === "connected") {
console.log("Connected:", wallet.session.account.address.toString());
}
// Fetch balance
const balance = await client.actions.fetchBalance(wallet.session.account.address);
console.log(`Balance: ${balance.toString()} lamports`);
```
### Using React Hooks
For React apps, wrap your app with the provider and use hooks:
#### 1. Create a Solana Client
```tsx
// lib/solana.ts
import { autoDiscover, createClient } from "@solana/client";
export const client = createClient({
cluster: "devnet",
walletConnectors: autoDiscover(),
});
```
#### 2. Wrap Your App with SolanaProvider
```tsx
// app/providers.tsx (or your root component)
import { SolanaProvider } from "@solana/react-hooks";
import { client } from "@/lib/solana";
export function Providers({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
#### 3. Use Hooks in Components
```tsx
import { useWalletConnection, useBalance } from "@solana/react-hooks";
function WalletPanel() {
const { connectors, connect, disconnect, wallet, status } = useWalletConnection();
const address = wallet?.account.address;
const balance = useBalance(address);
if (status === "connected") {
return (
;
}
```
### useWalletSession
Get the current wallet session for signing:
```tsx
function SignButton() {
const session = useWalletSession();
if (!session) return
Connect wallet first
;
return
Ready to sign with {session.account.address.toString()}