The Solana JSON-RPC API has dozens of methods. Most documentation lists them all without prioritisation. In practice, ~10 methods cover 95% of what production code does. Knowing which to use and how to use them well is more useful than memorising the full surface.
This piece is a reference for the JSON-RPC methods you'll actually use, with production patterns for each.
The High-Frequency Methods
These are the methods most production code calls heavily.
getAccountInfo
Read state for a single account.
const account = await connection.getAccountInfo(pubkey, "confirmed");
Use when: you need the data of one account.
Performance tips:
- Use
getMultipleAccountsInfoif you need multiple accounts in one call - Cache slow-changing data (token metadata, program ownership)
getMultipleAccountsInfo
Read state for multiple accounts in one call.
const accounts = await connection.getMultipleAccountsInfo(
[key1, key2, key3],
"confirmed"
);
Use when: you need 2+ accounts. Always prefer this over looping getAccountInfo.
Limit: ~100 accounts per call. Batch larger sets.
getProgramAccounts
Read all accounts owned by a program.
const accounts = await connection.getProgramAccounts(programId, {
filters: [
{ dataSize: 165 },
{ memcmp: { offset: 0, bytes: ownerKey.toBase58() } },
],
});
Use when: you need to enumerate accounts matching specific criteria.
Always use filters. Without them, you can pull megabytes of data.
Some RPC providers limit getProgramAccounts for cost reasons. Check your provider's policy.
getLatestBlockhash
Get a recent blockhash for transaction signing.
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
Use when: you're about to build and sign a transaction.
Use "confirmed" commitment for most cases. Don't cache; fetch fresh per transaction.
sendTransaction / sendRawTransaction
Submit a signed transaction.
const signature = await connection.sendTransaction(tx, signers, {
skipPreflight: true,
maxRetries: 0,
});
// Or with pre-serialised:
const signature = await connection.sendRawTransaction(tx.serialize(), {
skipPreflight: true,
maxRetries: 0,
});
Use when: submitting transactions for inclusion.
Production pattern: skipPreflight: true, maxRetries: 0. See our sendTransaction best practices.
confirmTransaction
Wait for a transaction to land.
const result = await connection.confirmTransaction(
{ signature, blockhash, lastValidBlockHeight },
"confirmed"
);
if (result.value.err) {
// Transaction failed during execution
}
Use when: after sending, you need to know whether it landed.
The newer signature-with-blockhash form is more reliable than the older signature-only form.
simulateTransaction
Run a transaction without committing.
const sim = await connection.simulateTransaction(tx);
console.log("Used CU:", sim.value.unitsConsumed);
console.log("Logs:", sim.value.logs);
Use when: testing during development, profiling CU usage, debugging.
In production, prefer skipPreflight: true and skip simulation. Simulate only for diagnostics.
getBalance
Get a wallet's SOL balance.
const balance = await connection.getBalance(pubkey, "confirmed");
console.log(balance); // Lamports
Use when: checking wallet funding, displaying balance to users.
getTokenAccountBalance
Get an SPL token account's balance.
const balance = await connection.getTokenAccountBalance(tokenAccountKey, "confirmed");
console.log(balance.value.uiAmount);
Use when: checking token holdings.
For checking all tokens a wallet holds, use getTokenAccountsByOwner.
getSignaturesForAddress
Get recent transaction signatures for an address.
const sigs = await connection.getSignaturesForAddress(pubkey, { limit: 100 });
Use when: building transaction history views, monitoring activity.
For production-grade indexing, dedicated indexing solutions are better than this method.
getTransaction
Fetch a specific transaction's details.
const tx = await connection.getTransaction(signature, {
commitment: "confirmed",
maxSupportedTransactionVersion: 0,
});
Use when: looking up specific transaction outcomes, debugging.
maxSupportedTransactionVersion: 0 is needed for versioned transactions (most modern transactions).
Subscription Methods (WebSocket)
For real-time updates instead of polling.
onAccountChange
Get notified when account state changes.
const subId = connection.onAccountChange(
pubkey,
(accountInfo, context) => {
handleChange(accountInfo, context.slot);
},
"confirmed"
);
// Cleanup:
await connection.removeAccountChangeListener(subId);
onLogs
Get notified of program log emissions.
const subId = connection.onLogs(
programId,
(logs, context) => {
if (logs.err === null) {
// Parse the events
}
},
"confirmed"
);
onSignature
Get notified when a specific transaction confirms.
const subId = connection.onSignature(
signature,
(result, context) => {
if (result.err === null) {
// Confirmed
}
},
"confirmed"
);
Use these instead of polling for reactive applications.
Less-Common But Useful Methods
getRecentPrioritizationFees
Get recent priority fee data, useful for tip strategy.
const fees = await connection.getRecentPrioritizationFees();
// Array of slot/fee pairs from recent slots
Use when: implementing dynamic priority fee strategy.
getSlot
Current slot number.
const slot = await connection.getSlot("processed");
Use when: timing decisions, freshness checks, health monitoring.
getEpochInfo
Current epoch state.
const epoch = await connection.getEpochInfo("confirmed");
Use when: monitoring epoch boundaries, staking-related logic.
getTokenAccountsByOwner
All token accounts owned by a wallet.
const accounts = await connection.getTokenAccountsByOwner(
ownerKey,
{ programId: TOKEN_PROGRAM_ID }
);
Use when: wallet UIs showing all tokens, portfolio analysis.
getInflationRate
Current inflation rate.
const rate = await connection.getInflationRate();
Use when: staking calculations, validator economics.
Methods to Avoid in Production
Some methods are heavy and worth avoiding for high-frequency use:
getProgramAccounts without filters. Pulls everything; expensive.
getBlock. Returns full block data; large response. Use only when you need block-level detail.
getConfirmedTransaction (deprecated). Use getTransaction instead.
getRecentBlockhash (deprecated). Use getLatestBlockhash instead.
Commitment Levels
Three commitment levels for most read methods:
"processed". Latest available state. Can be reorganised by short forks. Fastest.
"confirmed". Two-thirds of validators have voted. Stable for practical purposes. Good default.
"finalized". Fully final. Slowest but irrefutable.
For most production code, "confirmed" is right. Use "processed" only when latency matters and you can handle reorgs. Use "finalized" for high-value irrevocable decisions.
Common Patterns
Batch reads: Always use getMultipleAccountsInfo instead of looping getAccountInfo.
Filtered queries: Always use filters with getProgramAccounts.
Subscription over polling: For reactive apps, subscriptions beat polling for both performance and freshness.
Confirmation after sending: Always confirm transactions you've sent. Don't trust signature returned to mean landed.
Caching slow-changing data: Token metadata, program ownership, etc. Cache aggressively.
What to Do This Week
If you're auditing your RPC usage:
- Count your method calls. Which methods are you using most?
- Audit batched reads. Are you using
getMultipleAccountsInfowhere you should? - Audit filter usage. Always present on
getProgramAccountscalls? - Audit subscription vs polling. For reactive use cases, prefer subscriptions.
- Audit commitment levels. Are you using the right one for each use case?
- Profile latency per method. Some methods are heavy; high frequency on a heavy method is a problem.
Try BoltTx
For sendTransaction specifically:
import { Connection } from "@solana/web3.js";
const connection = new Connection(
"https://bolttx.io/?api-key=YOUR_API_KEY",
"processed"
);
const signature = await connection.sendTransaction(tx, signers, {
skipPreflight: true,
maxRetries: 0,
});
Free tier signup. Pair with whatever read provider fits your read traffic.
FAQ
Where's the canonical reference? Solana's official JSON-RPC API documentation. The methods covered here are the practically-used subset.
Are RPC methods standardised across providers? The method names and parameters are standard. Behaviour and rate limits vary by provider.
Can I batch multiple JSON-RPC calls in one HTTP request? JSON-RPC 2.0 supports batching at the protocol level; provider support varies. Most don't get notable speedup from batching.
What's the latency cost of each method? Varies. Reads are typically tens to hundreds of milliseconds; writes have additional confirmation latency.
Should I use the deprecated method names? No. They may stop working in future versions. Use the current names.