solana-kit
Solana Kit Development Guide
A comprehensive guide for building Solana applications with @solana/kit - the modern, tree-shakeable, zero-dependency JavaScript SDK from Anza.
Overview
Solana Kit (formerly web3.js 2.0) is a complete rewrite of the Solana JavaScript SDK with:
- Tree-shakeable: Only ship code you use (-78% bundle size)
- Zero dependencies: No third-party packages
- Functional design: Composable, no classes
- 10x faster crypto: Native Ed25519 support
- TypeScript-first: Full type safety
Quick Start
Installation
npm install @solana/kit
For specific program interactions:
npm install @solana-program/system @solana-program/token
Minimal Example
import {
createSolanaRpc,
createSolanaRpcSubscriptions,
generateKeyPairSigner,
lamports,
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
const LAMPORTS_PER_SOL = BigInt(1_000_000_000);
async function transferSol() {
// 1. Connect to RPC
const rpc = createSolanaRpc("https://api.devnet.solana.com");
const rpcSubscriptions = createSolanaRpcSubscriptions("wss://api.devnet.solana.com");
// 2. Create signers
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// 3. Get blockhash
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// 4. Build transaction with pipe
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(sender.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstruction(
getTransferSolInstruction({
amount: lamports(LAMPORTS_PER_SOL / BigInt(10)), // 0.1 SOL
destination: recipient.address,
source: sender,
}),
tx
)
);
// 5. Sign
const signedTx = await signTransactionMessageWithSigners(transactionMessage);
// 6. Send and confirm
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
await sendAndConfirm(signedTx, { commitment: "confirmed" });
console.log("Signature:", getSignatureFromTransaction(signedTx));
}
Core Concepts
1. RPC Connections
Kit separates HTTP and WebSocket connections:
import { createSolanaRpc, createSolanaRpcSubscriptions } from "@solana/kit";
// HTTP for requests
const rpc = createSolanaRpc("https://api.devnet.solana.com");
// WebSocket for subscriptions
const rpcSubscriptions = createSolanaRpcSubscriptions("wss://api.devnet.solana.com");
// Make RPC calls
const slot = await rpc.getSlot().send();
const balance = await rpc.getBalance(address).send();
const { value: blockhash } = await rpc.getLatestBlockhash().send();
2. Signers
Kit uses signer interfaces instead of keypairs directly:
import {
generateKeyPairSigner,
createKeyPairSignerFromBytes,
address,
} from "@solana/kit";
// Generate new signer
const signer = await generateKeyPairSigner();
console.log("Address:", signer.address);
// From existing secret key (Uint8Array)
const existing = await createKeyPairSignerFromBytes(secretKeyBytes);
// Create address from string
const addr = address("11111111111111111111111111111111");
3. Transaction Building with Pipe
Kit uses functional composition via pipe:
import {
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
appendTransactionMessageInstructions,
prependTransactionMessageInstructions,
} from "@solana/kit";
const tx = pipe(
createTransactionMessage({ version: 0 }), // Create v0 message
(tx) => setTransactionMessageFeePayer(payer.address, tx), // Set fee payer
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx), // Set lifetime
(tx) => appendTransactionMessageInstruction(instruction1, tx), // Add instruction
(tx) => appendTransactionMessageInstructions([instruction2, instruction3], tx), // Add multiple
);
4. Signing Transactions
import {
signTransactionMessageWithSigners,
partiallySignTransactionMessageWithSigners,
getSignatureFromTransaction,
} from "@solana/kit";
// Sign with all signers in the transaction
const signedTx = await signTransactionMessageWithSigners(transactionMessage);
// Partial signing (for multisig)
const partiallySignedTx = await partiallySignTransactionMessageWithSigners(
transactionMessage
);
// Get signature before sending
const signature = getSignatureFromTransaction(signedTx);
5. Sending Transactions
import {
sendAndConfirmTransactionFactory,
sendTransactionWithoutConfirmingFactory,
getBase64EncodedWireTransaction,
} from "@solana/kit";
// Send with confirmation (recommended)
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
await sendAndConfirm(signedTx, { commitment: "confirmed" });
// Send without waiting for confirmation
const send = sendTransactionWithoutConfirmingFactory({ rpc });
await send(signedTx, { commitment: "confirmed" });
// Manual encoding (low-level)
const encoded = getBase64EncodedWireTransaction(signedTx);
await rpc.sendTransaction(encoded, { encoding: "base64" }).send();
6. Fetching Accounts
import {
fetchEncodedAccount,
fetchEncodedAccounts,
assertAccountExists,
} from "@solana/kit";
// Fetch single account
const account = await fetchEncodedAccount(rpc, address);
if (account.exists) {
console.log("Lamports:", account.lamports);
console.log("Owner:", account.programAddress);
console.log("Data:", account.data);
}
// Fetch multiple accounts
const accounts = await fetchEncodedAccounts(rpc, [addr1, addr2, addr3]);
// Assert account exists (throws if not)
assertAccountExists(account);
Package Reference
Core Package
| Import | Description |
|---|---|
@solana/kit |
Main package - includes everything below |
Individual Packages
| Package | Purpose |
|---|---|
@solana/rpc |
RPC client creation |
@solana/rpc-subscriptions |
WebSocket subscriptions |
@solana/signers |
Signing interfaces |
@solana/addresses |
Address utilities |
@solana/keys |
Key generation |
@solana/transactions |
Transaction compilation |
@solana/transaction-messages |
Message building |
@solana/accounts |
Account fetching |
@solana/codecs |
Data encoding/decoding |
@solana/errors |
Error handling |
Program Packages
| Package | Program |
|---|---|
@solana-program/system |
System Program |
@solana-program/token |
SPL Token |
@solana-program/token-2022 |
Token Extensions |
@solana-program/memo |
Memo Program |
@solana-program/compute-budget |
Compute Budget |
@solana-program/address-lookup-table |
Lookup Tables |
Common Patterns
Pattern 1: Helper Function for Send & Confirm
import {
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
getSignatureFromTransaction,
CompilableTransactionMessage,
TransactionMessageWithBlockhashLifetime,
Commitment,
} from "@solana/kit";
function createTransactionSender(rpc: Rpc, rpcSubscriptions: RpcSubscriptions) {
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
return async (
txMessage: CompilableTransactionMessage & TransactionMessageWithBlockhashLifetime,
commitment: Commitment = "confirmed"
) => {
const signedTx = await signTransactionMessageWithSigners(txMessage);
await sendAndConfirm(signedTx, { commitment, skipPreflight: false });
return getSignatureFromTransaction(signedTx);
};
}
// Usage
const sendTx = createTransactionSender(rpc, rpcSubscriptions);
const signature = await sendTx(transactionMessage);
Pattern 2: Reusable Transaction Builder
import {
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
IInstruction,
} from "@solana/kit";
async function buildTransaction(
rpc: Rpc,
feePayer: Address,
instructions: IInstruction[]
) {
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
return pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions(instructions, tx)
);
}
Pattern 3: Add Compute Budget
import {
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
} from "@solana-program/compute-budget";
const computeInstructions = [
getSetComputeUnitLimitInstruction({ units: 200_000 }),
getSetComputeUnitPriceInstruction({ microLamports: 1000n }),
];
const tx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(payer.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) => prependTransactionMessageInstructions(computeInstructions, tx), // Prepend!
(tx) => appendTransactionMessageInstruction(mainInstruction, tx),
);
Pattern 4: Versioned Transactions with Lookup Tables
import {
setTransactionMessageAddressLookupTable,
} from "@solana/kit";
// Fetch lookup table
const lookupTableAccount = await fetchAddressLookupTable(rpc, lookupTableAddress);
const tx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(payer.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) => setTransactionMessageAddressLookupTable(tx, lookupTableAccount),
(tx) => appendTransactionMessageInstructions(instructions, tx),
);
Type Safety
Kit provides comprehensive TypeScript types:
import type {
Address,
Signature,
Lamports,
TransactionMessage,
Rpc,
RpcSubscriptions,
KeyPairSigner,
} from "@solana/kit";
// Addresses are branded strings
const addr: Address = address("11111111111111111111111111111111");
// Lamports are branded bigints
const amount: Lamports = lamports(1_000_000_000n);
// Type-safe RPC responses
const response = await rpc.getBalance(addr).send();
// response.value is typed as Lamports
Performance Tips
-
Import only what you need - Kit is tree-shakeable
// Good - only imports what's used import { createSolanaRpc, generateKeyPairSigner } from "@solana/kit"; // Also good - use subpackages for smaller bundles import { createSolanaRpc } from "@solana/rpc"; import { generateKeyPairSigner } from "@solana/signers"; -
Reuse RPC connections - Don't create per request
// Create once const rpc = createSolanaRpc(endpoint); // Reuse everywhere await rpc.getBalance(addr1).send(); await rpc.getBalance(addr2).send(); -
Batch requests when possible
// Fetch multiple accounts in one request const accounts = await fetchEncodedAccounts(rpc, [addr1, addr2, addr3]); -
Use skipPreflight carefully - Faster but no simulation
await sendAndConfirm(tx, { commitment: "confirmed", skipPreflight: true });
Error Handling
import { isSolanaError, SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS } from "@solana/errors";
try {
await sendAndConfirm(signedTx, { commitment: "confirmed" });
} catch (error) {
if (isSolanaError(error, SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS)) {
console.error("Not enough SOL for transaction");
} else if (isSolanaError(error)) {
console.error("Solana error:", error.context);
} else {
throw error;
}
}
Migration from web3.js 1.x
See the separate migration skill or use @solana/compat for interoperability:
import {
fromLegacyPublicKey,
fromLegacyKeypair,
fromVersionedTransaction,
fromLegacyTransactionInstruction,
} from "@solana/compat";
// Convert legacy PublicKey to Kit Address
const address = fromLegacyPublicKey(legacyPublicKey);
// Convert legacy Keypair to Kit CryptoKeyPair (async)
const keyPair = await fromLegacyKeypair(legacyKeypair);
// Convert legacy VersionedTransaction to Kit Transaction
const kitTransaction = fromVersionedTransaction(legacyVersionedTx);
// Convert legacy TransactionInstruction to Kit Instruction
const kitInstruction = fromLegacyTransactionInstruction(legacyInstruction);
Note: The compat package converts FROM legacy TO Kit types. For reverse conversion, you may need to manually construct legacy objects.
Performance Benchmarks
Kit delivers significant performance improvements over web3.js 1.x:
| Metric | web3.js 1.x | @solana/kit | Improvement |
|---|---|---|---|
| Keypair Generation | ~50ms | ~5ms | 10x faster |
| Transaction Signing | ~20ms | ~2ms | 10x faster |
| Bundle Size | 311KB | 226KB | 26% smaller |
| Confirmation Latency | ~400ms | ~200ms | ~200ms faster |
Benchmarks from Triton One's Ping Thing service and Solana Explorer testing
Why It's Faster
- Native Ed25519: Uses browser/runtime native crypto APIs
- Zero Dependencies: No third-party library overhead
- Tree-Shakeable: Only imports code you use
- No Classes: Functional design enables better optimization
Resources
Skill Structure
solana-kit/
├── SKILL.md # This file
├── resources/
│ ├── packages-reference.md # Complete package documentation
│ └── api-quick-reference.md # Quick lookup table
├── examples/
│ ├── transfer-sol/ # Basic SOL transfer
│ ├── create-token/ # SPL token creation
│ ├── fetch-accounts/ # Account fetching & decoding
│ └── subscriptions/ # Real-time subscriptions
├── templates/
│ └── project-template.ts # Copy-paste starter
└── docs/
├── advanced-patterns.md # Complex patterns
└── troubleshooting.md # Common issues
More from sendaifun/skills
helius
Build Solana applications with Helius infrastructure. Covers transaction sending (Sender), asset/NFT queries (DAS API), real-time streaming (WebSockets, Laserstream), event pipelines (webhooks), priority fees, wallet analysis, and agent onboarding.
215pumpfun
Complete PumpFun Protocol guide for building token launches, bonding curves, and AMM integrations on Solana. Covers Pump Program (token creation, buy/sell on bonding curves), PumpSwap AMM (liquidity pools, swaps), fee structures, creator fees, and SDK integration.
165meteora
Complete Meteora DeFi SDK suite for building liquidity pools, AMMs, bonding curves, vaults, token launches, and zap operations on Solana. Use when integrating DLMM, DAMM v2, DAMM v1, Dynamic Bonding Curves, Alpha Vaults, Zap, or Stake-for-Fee functionality.
164vulnhunter
Security vulnerability detection and variant analysis skill. Use when hunting for dangerous APIs, footgun patterns, error-prone configurations, and vulnerability variants across codebases. Combines sharp edges detection with variant hunting methodology.
145raydium
Complete Raydium Protocol SDK - the single source of truth for integrating Raydium on Solana. Covers SDK, Trade API, CLMM, CPMM, AMM pools, LaunchLab token launches, farming, CPI integration, and all Raydium tools.
144coingecko
Complete CoinGecko Solana API integration for token prices, DEX pool data, OHLCV charts, trades, and market analytics. Use for building trading bots, portfolio trackers, price feeds, and on-chain data applications.
140