Back to Common Questions

How do I get all transactions for a Solana program?

Updated August 2026

For a low-volume program, paginate getSignaturesForAddress and fetch each transaction. For a busy program, that approach will not finish — you need to process blocks and filter by program ID instead, which is what an indexing pipeline does.

There is also a correctness trap in the RPC approach that catches people out, covered below.

Why does the RPC approach break down?

Pagination is sequential. getSignaturesForAddress returns up to 1,000 signatures per call. A program with millions of transactions means thousands of sequential calls, each followed by fetching the transactions themselves. This does not parallelise well and takes a very long time.

Rate limits. Providers throttle this pattern quickly, because it is expensive to serve.

History may not be there. Standard RPC nodes prune. Older transactions may be unavailable regardless of how patiently you paginate.

Cross-program invocations are missed. This is the correctness problem. If your program is invoked by another program — a router, an aggregator, a wrapper — the transaction may not be attributed to your program's address in the way you expect. Naive signature enumeration misses activity that genuinely involved your program.

What does the complete approach look like?

Process blocks directly and filter by program ID, including inner instructions.

A Substreams module receives each Solana block, examines the instructions in every transaction — top-level and inner — and emits records where your program appears. Because historical segments process in parallel, a program's full history is bounded by parallel throughput rather than by sequential pagination.

The same module then continues against live blocks, so you are not building a separate real-time path.

RPC paginationBlock processing
Complete historyLimited by pruningFull, from genesis
SpeedSequentialParallel
Inner instructionsMissedIncluded
Rate limitsYesNo
DecodingYoursIn the module

What should the output look like?

Decide the shape before you run a large backfill, because re-running to add a field is avoidable work.

Most teams want: signature, slot, block time, the instruction that ran, decoded arguments, the accounts involved, and success or failure. Store slot and signature on every row regardless — you need them for deduplication and for reasoning about reorgs.

If the program is Anchor-based, its IDL gives you instruction names and argument types. If there is no IDL, the discriminator can be derived from the program's Rust source — an approach the agent skills handle, and which was verified in a published evaluation.

How do I check I have everything?

Pick a slot range, extract it, and compare against a block explorer for the same range. Look specifically for transactions where your program was invoked by another program — that is where the RPC approach and the complete approach diverge, and where a silent gap would otherwise live.


Frequently asked questions

Is getSignaturesForAddress ever the right tool? Yes, for low-volume programs, recent activity, or quick exploration.

How do I get transactions from before my RPC node's pruning window? Use a source that serves full history rather than a standard RPC node.

Do I need the IDL? It makes decoding straightforward. Without one, the discriminator can be derived from source.


Get an API key at thegraph.market — no personal information required.

Related: How far back can Yellowstone gRPC replay Solana data? · How do I backfill historical blockchain data?