RPC & WebSockets In Depth
Solana clients never talk to the ledger as a raw database; they talk to RPC nodes that expose JSON-RPC over HTTP and real-time updates over WebSockets.
Search across all documentation pages
Solana clients never talk to the ledger as a raw database; they talk to RPC nodes that expose JSON-RPC over HTTP and real-time updates over WebSockets.
Wallet balances, program account fetches, transaction sends, signature waits, and (on many providers) digital-asset galleries all ride that access layer.
This page is the section umbrella: HTTP vs subscriptions, cheap vs expensive methods, core RPC vs DAS, and how providers, pagination, and fee/simulation APIs complete a production stack.
@solana/kit clients; choosing poll vs subscribe; planning mainnet GPA and NFT portfolio reads; selecting provider features and fee estimation paths.RPC (Remote Procedure Call) is how applications observe and submit work on a Solana cluster.
An RPC node runs (or fronts) validator software such as Agave, serves JSON-RPC 2.0 over HTTPS, and typically exposes a companion WebSocket endpoint for subscriptions.
Clients do not need to run a validator; they need a correct RPC URL for the cluster they mean (mainnet-beta, devnet, testnet, or localnet).
Requests are JSON-RPC objects: method names like getBalance or sendTransaction, optional params, and an id echoed in the response.
Responses carry either a result or an error with a code and message; application code should treat HTTP 429, timeouts, and JSON-RPC errors as first-class failure modes.
Commitment (processed, confirmed, finalized) is orthogonal to method choice: it tells the node how deep in consensus a read or notification must be before it answers.
Reading at processed is fast and fork-sensitive; reading at finalized is slower and safer for irreversible product decisions.
The HTTP path is request/response: get this account, send this transaction, simulate this payload, return once.
The WebSocket path is long-lived: subscribe once, receive push notifications when an account changes, a signature reaches commitment, or matching logs appear.
HTTP and WebSocket are two faces of the same RPC product, not two ledgers; you still pick one cluster and one commitment policy.
Core read methods hydrate application state from accounts the runtime already knows by pubkey: balances, single-account data, and batched multi-account loads.
getProgramAccounts asks a harder question: return every account owned by a program (optionally filtered), which forces a scan of program-owned state and is the classic source of mainnet timeouts and rate limits.
DAS (Digital Asset Standard) APIs extend JSON-RPC with asset-centric methods (getAsset, getAssetsByOwner, search/group queries) backed by provider indexers that stitch token programs, metadata, and compression trees into one model.
DAS is not a required Agave built-in on every public URL; it is a provider capability you enable when NFT, cNFT, and portfolio UX would be painful on raw token walks alone.
Providers (managed RPC, DAS, webhooks, gRPC) and self-hosted validators trade ops burden for control; production apps leave free public endpoints behind.
Pagination and efficiency keep you under RPS and payload caps: batch known pubkeys, cursor signature history, filter GPA tightly, and move discovery to indexers when sets grow.
Simulation and priority-fee APIs sit on the write path: estimate compute units and micro-lamports per CU, and use simulateTransaction to surface program errors without spending mainnet fees on every dry run.
Together these pieces form one map:
Client (@solana/kit, wallet, backend worker)
|
+-- HTTPS JSON-RPC --------> RPC / provider edge
| reads, send, simulate, fees
|
+-- WSS subscriptions -----> same cluster surface
| account / logs / signature / slot
|
+-- DAS methods (optional) -> DAS-enabled provider
getAsset, getAssetsByOwner, searchAssetsSibling pages in this section zoom each branch; this page keeps the whole diagram in view.
A typical read is one POST with Content-Type: application/json.
The node resolves the method against its bank snapshot at the requested commitment, encodes account data (base64, base58, or jsonParsed where supported), and returns.
sendTransaction accepts a serialized, signed transaction and returns a signature handle; durability still requires polling or a WebSocket subscription until the chosen commitment is reached.
App builds + signs tx
|
v
HTTP sendTransaction --> signature S
|
+-- poll getSignatureStatuses(S), or
+-- signatureSubscribe(S) over WSS
|
v
commitment ladder: processed -> confirmed -> finalizedThe client opens wss://..., sends a *Subscribe method, and receives a subscription id plus later *Notification messages.
Common subscriptions:
| Subscription | Fires when |
|---|---|
accountSubscribe | Account lamports or data change |
logsSubscribe | Transactions match a filter (e.g. mentions) |
signatureSubscribe | Transaction reaches the subscription commitment |
slotSubscribe | New slots progress |
Notifications are push views from the node you connected to, not a global ordered bus across all providers.
Unsubscribe (or abort the kit subscription) when components unmount so connections do not leak.
| Pattern | Methods | Cost posture |
|---|---|---|
| Known pubkey | getBalance, getAccountInfo, getMultipleAccounts | Low to medium; batch multi-get |
| Program scan | getProgramAccounts | High without filters; may timeout |
| History | getSignaturesForAddress, getTransaction | Medium to high; paginate and cache |
| Assets | DAS getAsset / getAssetsByOwner | Provider-indexed; plan-dependent |
| Live UI | WebSocket subscriptions | Connection + notify load |
Always prefer known-pubkey reads when an indexer, PDA derivation, or prior response already gave you addresses.
Use GPA with dataSize and memcmp filters only when you must discover accounts by layout; never default to unfiltered GPA on mainnet for large programs.
When GPA still cannot meet product scale, move discovery to Geyser/Yellowstone-style pipelines or a dedicated indexer rather than retrying the same scan.
Core RPC answers "what is the account at this address?"
DAS answers "what digital assets does this owner hold, and what metadata/compression proof do I need to render or verify them?"
Use core RPC (and kit) for custom program accounts, fee payers, and transaction submission.
Use DAS for NFT galleries, collection queries, and compressed assets where the provider has already paid the indexing cost.
Managed providers front Agave (or equivalent) with load balancers, API keys, and optional sidecars (DAS, webhooks, enhanced fee estimates).
Public cluster URLs exist for learning and light devnet work; they throttle aggressively and are not a production plan.
Efficiency rules that apply everywhere:
getMultipleAccounts (often ~50-100 keys per call, subject to provider docs).getSignaturesForAddress with before / until cursors and a limit.Before landing sensitive transactions, clients often:
simulateTransaction with options such as sigVerify: false and replaceRecentBlockhash to read unitsConsumed, logs, and errors.getRecentPrioritizationFees (and/or provider percentile fee APIs) for accounts involved in the lock set.Simulation is not a substitute for mainnet confirmation; it reduces avoidable failures and underpriced inclusion.
| Concern | Primary page | Builder takeaway |
|---|---|---|
| JSON-RPC shape, commitment, rate limits | RPC Basics | Set commitment explicitly; treat 429 as normal |
| Balance, account info, multi-get, GPA overview | Core RPC Methods | Prefer multi-get over chatty single reads |
memcmp / dataSize, Anchor discriminators | getProgramAccounts & Filters | Filter server-side or do not scan |
| Cursors, batching, avoiding heavy scans | Pagination & Efficiency | GPA is not paginated; design discovery offline |
| Fee samples, simulate options, CU headroom | Priority Fee & Simulation APIs | Estimate then send; log CU and fee choices |
| Managed vs self-host, feature matrices | RPC Providers | Match DAS/gRPC needs to vendor; keep keys out of source |
WebSocket subscriptions and DAS have dedicated how-to pages in this section; operationally they still hang off the same provider URL and commitment policy described above.
Separate HTTP RPC, WSS, and DAS configuration even when one vendor issues all three.
Pin commitment per action class in one module rather than scattering string literals.
For write-heavy products, combine simulation-driven CU limits with dynamic priority fees and a confirmation path that does not treat sendTransaction success as settlement.
| Need | Stay on core RPC / WS | Leave for indexer / gRPC / webhooks |
|---|---|---|
| Wallet balance + few PDAs | Yes | No |
| Live single-account UI | WebSocket | Optional |
| Full program analytics | No | Yes |
| Large NFT portfolio + cNFTs | DAS if available | Custom indexer if DAS insufficient |
| Millisecond multi-account streams | Limited | Yellowstone / Geyser class |
@solana/kit 7.0.0 provides createSolanaRpc for HTTP and createSolanaRpcSubscriptions for WSS on standard methods.
DAS often uses direct fetch or a provider SDK until you wrap it; keep DAS base URLs configurable next to kit RPC URLs.
CLI (solana against the same RPC URL) is useful for debugging the identical methods your app calls.
signatureSubscribe; durability is the commitment level you wait for afterward.It is the JSON-RPC (and WebSocket) API surface through which clients read accounts, submit transactions, and observe commitment on a chosen cluster.
Use HTTP for request/response reads, sends, simulation, and fee samples; use WebSockets when you need push updates for accounts, logs, or signature confirmation without tight polling loops.
Many product actions use confirmed for responsive UX; use finalized before irreversible external effects; treat processed as optimistic only.
Unfiltered or weakly filtered scans timeout or hit provider limits; add dataSize and memcmp filters or move discovery to an indexer.
getMultipleAccounts loads known pubkeys in a batch; GPA discovers accounts by owner (and filters) when you do not already know the addresses.
DAS is a standardized asset-oriented API offered by indexing providers on top of chain data; it is not guaranteed on every Agave public endpoint.
Usually no for arbitrary layouts; DAS targets digital assets (tokens, NFTs, cNFTs). Custom program state still uses core RPC, filters, or your own indexer.
No. Notifications honor the commitment you subscribed with; processed updates can roll back on forks, so UI must remain reversible until deeper commitment.
Signature history uses cursors (before / until) and limit; multi-get is chunked by pubkey list; GPA is not offset-paginated, so filters or external indexes carry large discovery; DAS often exposes page / limit on provider APIs.
Managed options include Helius, Triton, and QuickNode for hosted RPC plus optional DAS, gRPC, or webhooks; self-hosting Agave trades ops cost for control; public free RPC is for light non-production use.
Simulate to estimate compute units and catch program errors; sample recent prioritization fees (or provider percentiles) to set CU price; then send and wait for commitment.
No. Kit 7.0.0 types and wraps the same JSON-RPC and subscription surfaces; you still choose methods, commitment, filters, and providers correctly.
No. Use authenticated provider endpoints (and often separate HTTP/WSS/DAS URLs), rate-limit client-side, and plan failover for critical paths.
When you need full historical analytics, large program-wide discovery, or multi-account streams that exceed filtered GPA and subscription capacity.
Start with RPC Basics for commitment and client setup, then Core RPC Methods for everyday reads; open GPA, pagination, fees, and providers as those pain points appear.
getAccountInfo, getBalance, getMultipleAccounts, GPA overviewmemcmp, dataSize, and safe program scanssimulateTransaction, and CU headroomStack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, Rust 1.91.1, and @solana/kit 7.0.0.
Reviewed by Chris St. John·Last updated Jul 15, 2026