BLOG
Developers

getProgramAccounts Alternatives: Stop Scanning, Start Streaming

getProgramAccounts is the most expensive and most limited method in the Solana RPC API, and most calls to it should be a gRPC subscription, an indexer query, getMultipleAccounts, or a provider index. Why it is costly and the alternative for each use case.

Sourav Mishra

Sourav Mishra · Solutions Engineer

Sep 4, 20267 min read

getProgramAccounts Alternatives: Stop Scanning, Start Streaming

getProgramAccounts retrieves all accounts belonging to the given program with optional filtering in one request. It makes the method extremely costly, rate-limited and prone to throttling, making it the most expensive, rate-limited and throttled call in Solana RPC API. There are multiple options to use instead for anything else than a one-shot request: Geyser gRPC subscription streaming the accounts continuously, indexer pre-populated once for cheap querying, getMultipleAccounts if the addresses are known, or provider-side index like DAS API for NFTs. Below you'll find the explanation of why the call is costly, what are the use-cases for it and alternatives for each of the use cases.

Description of the method and the source of the cost

getProgramAccounts(programId, filters) requests the node to fetch all accounts with the given program as the owner and, optionally, filter them by data size and by memcmp filters on the account data. Node must look into its account index with the given owner, apply the filters and serialize the response.

The request is cheap for a small program owning just a few hundred accounts. On the contrary, a token program, a major decentralized exchange or a lending protocol owns millions of accounts. Even with tight filters, the node does lots of scanning and produces a huge response. Providers limit this call (by rate, response size or require filters and dataSlice), weight the call very heavy in credit pricing and may offload the call to the specialized hardware. Applications repeatedly calling this method in a loop to monitor accounts are the most common cause of throttling and unexpected invoicing.

Use cases in which the method remains a good choice

  • One-shot discovery: finding all accounts of the given kind to seed an indexer or a cache.
  • Small programs: programs controlled by the user with a limited number of accounts.
  • Development: exploring a program's accounts while developing it.

In all three cases the use of dataSlice to get only the necessary bytes and applying tight memcmp filters on the discriminator is advised to reduce the size of the response.

Alternative 1: subscribe to the accounts with Yellowstone gRPC

If the reason to call getProgramAccounts repeatedly is to detect changes in accounts, a subscription is better than scanning. A Yellowstone gRPC account filter by the owner program (same memcmp conditions) will stream all writes to each matching account. It eliminates the loop and provides lower latency than any polling period.

Alternative 2: build an indexer and query your own storage

When the goal is to answer some aggregate questions (e.g., all holders of a mint, all positions above a certain threshold, all pools for the given pair) the proper solution is a database built from the stream and queried using SQL or a key-value lookup. Seed the indexer with a single getProgramAccounts call or archival backfill and keep it up-to-date via gRPC to avoid scanning the chain for the same question again.

Alternative 3: getMultipleAccounts for known addresses

If the target accounts are known (they are derived addresses or have been identified by an indexer), fetch them directly. getMultipleAccounts returns up to one hundred accounts per call and takes a fraction of the cost of a scan over a whole program. Many looping implementations of getProgramAccounts actually request "fetch these fifty accounts I already know" in the wrong way.

Accounts like associated token accounts, PDAs and pool accounts should be derived, not searched.

Alternative 4: provider-side indexes

There are some questions that are asked often enough for providers to maintain their own indices. The most famous example is NFTs: Digital Asset Standard (DAS) API can answer "which assets does this wallet own" and "what is the metadata of a given asset" for standard and compressed NFTs without any program scans from the client side. NFT and DAS indexing on Solana explains the issue. For token holders, balances and other questions check whether there is an index provided by your provider.

Decision framework by the question

If the continuous usage of the method is still needed

  • Always use memcmp filters on the discriminator and use dataSlice to fetch only the necessary bytes.
  • Request data at the confirmed commitment level; finalized commitment will give you the old snapshot anyway without any gain for a scan.
  • Cache the results and compute the diffs instead of re-fetching the whole datasets.
  • Prefer pricing models that don't weight the method specifically.
  • Consider getting a [dedicated node](https://orbitflare.com/products/dedicated-nodes) if the scans are critical for your product: it will have a fixed hardware cost and no per-call costs and reduce the throttling risk.

Conclusion

getProgramAccounts is a discovery method that turned into a polling method. It explains the throttling of applications and invoice increases. Substitute endless loops with Yellowstone gRPC subscription when you need to detect changes, with indexer for fast aggregate queries, with getMultipleAccounts if the addresses are known or with a provider-side index like DAS if you need to work with NFTs. Keep using the method for one-shot discovery with dataSlice and filters.

OrbitFlare's gRPC service is the streaming alternative to getProgramAccounts, and the RPC plans are priced by requests per second with no method weighting, so the call costs the same as other methods when you need it.

Resources

  1. getProgramAccounts RPC method (Solana docs)
  2. getMultipleAccounts RPC method (Solana docs)
  3. Yellowstone gRPC (GitHub)
  4. Digital Asset Standard API (Metaplex docs)
  5. NFT and DAS indexing on Solana (OrbitFlare)
  6. Jetstream and Yellowstone gRPC streaming (OrbitFlare)
  7. OrbitFlare dedicated nodes
  8. OrbitFlare RPC plans

FAQ

Because one call can cost the node as much as thousands of ordinary reads. Providers protect the fleet by limiting it specifically.

Not in the standard API; the response is the full matching set. Pagination is what an indexer gives you.

You can, with a `memcmp` filter on the mint or owner, but the token program owns an enormous number of accounts and the call is slow and often refused. Use `getTokenAccountsByOwner` for a wallet's tokens, or an index for a mint's holders.

Subscribe. WebSockets `programSubscribe` for small cases, Yellowstone gRPC accounts filters for anything larger. [WebSockets vs gRPC](/blog/developers/solana-websockets-vs-grpc) covers the choice.

Cheaper, not cheap. The node still scans and filters; `dataSlice` only shrinks the response. Use it always, and still avoid the loop.

Very likely, if anything in your code calls it on an interval. Check method-level usage; the fix is one of the alternatives above, usually a gRPC subscription.

Related articles