Free-tier maxxing¶
About 110 requests/second of Solana RPC, for $0/month — and more if you want it. No single free tier gets you there; the best one on its own is 25 req/s. Stacking nine endpoints behind one local address does, because no single key ever sees more than a fraction of your traffic.
This page is the arithmetic and the config.
Is there a free Solana RPC endpoint?¶
Yes, several, at three different levels of commitment.
No signup at all. Two endpoints need no account and no key:
https://api.mainnet-beta.solana.com # Solana Foundation
https://solana-rpc.publicnode.com # PublicNode, operated by Allnodes
The Solana Foundation endpoint is documented at roughly 10 req/s (100 requests per 10 seconds per IP), 4 req/s for any single method, 40 concurrent connections, and 100 MB per 30 seconds. Solana's own cluster documentation says plainly: "The public RPC endpoints are not intended for production applications."
PublicNode publishes no rate limits at all, which cuts both ways:
there is no documented cap to design against, and no commitment that today's throughput survives
tomorrow. Verified serving mainnet 2026-09-05. Treat it as free capacity of unknown size — start it
with a conservative max_rps, watch rpc_plane_rate_limited_total and the 429 rate, and raise the
cap until one of them moves.
A third, https://public.rpc.solanavibestation.com, also needs no key, but it is too small to stack.
It publishes no limit, and when measured on 2026-11-06 it held about 1 req/s, a tenth of the smallest
leg below, so it is left out of the config. The free key from
the same provider is in.
Free tiers with an account. Seven providers give you real capacity for a signup and no card:
| Provider | Monthly allowance | Rate limit | Notes |
|---|---|---|---|
| Alchemy | 30M compute units | 25 req/s | ~3M standard reads. Largest on dedicated infrastructure |
| Chainstack | 3M request units | 25 req/s | 1 RU per call, so 3M calls. Renews monthly |
| dRPC | 210M compute units / 30 days | unpublished | ~10.5M calls — the largest allowance here, but served over dRPC's public node pool |
| OnFinality | 400K response units per day | 40 RU/s → 20 calls/s | 2 RU per call, so ~200K calls/day (~6M/month). Note the allowance is daily |
| QuickNode | 10M credits (trial) | 15 req/s | Does not sell overage; the endpoint stops when credits run out |
| Helius | 1M credits | 10 req/s | Only 1 sendTransaction/s — the binding limit if you write |
| Solana Vibe Station | none — unmetered | 5 req/s | Flat-rate provider, so there is no allowance to exhaust; the rate is the only ceiling. 1 sendTransaction/s |
Two of those need reading carefully. OnFinality's cap is in response units, not requests — every Solana method costs 2 RU, so 40 RU/s is 20 calls/s. And dRPC's free tier runs on its public node pool, which is slower and less reliable than its paid endpoints; it belongs in the stack as headroom, not as the leg you route latency-sensitive traffic to.
Free forever? Alchemy, Chainstack, Helius and dRPC renew (dRPC every 30 days from signup); OnFinality renews daily. Solana Vibe Station has nothing to renew, because it meters nothing. QuickNode's is a trial — 10M credits once, not 10M a month. Treat QuickNode as the leg that disappears. The two no-signup endpoints have no allowance to exhaust, only unpublished (Foundation: published) throughput ceilings.
Alchemy, QuickNode and Helius verified 2026-09-05; Chainstack, dRPC and OnFinality 2026-09-06; Solana Vibe Station 2026-11-06, with its limits also measured. Rates and weights for all of them are in provider pricing.
What stacking actually buys¶
Adding the caps:
| Rate | Monthly allowance | |
|---|---|---|
| Alchemy free | 25 req/s | 30M CU (~3M reads) |
| Chainstack free | 25 req/s | 3M RU (3M reads) |
| OnFinality free | 20 calls/s | 400K RU/day (~6M reads) |
| QuickNode trial | 15 req/s | 10M credits (~333k reads) |
| Helius free | 10 req/s | 1M credits (~1M reads) |
| Solana Foundation | 10 req/s | unmetered, no SLA |
| Solana Vibe Station free | 5 req/s | unmetered, not for production |
| Subtotal | ~110 req/s | ~13.3M metered reads, plus two unmetered legs |
| dRPC free | unpublished | 210M CU/30d (~10.5M calls), public pool |
| PublicNode | unpublished | unmetered, no SLA |
dRPC and PublicNode are left out of the subtotal deliberately — neither publishes a rate limit, so adding a number would be inventing one. In practice both are extra headroom on top of the 110, and dRPC's 10.5M calls would nearly double the monthly allowance if you use it.
Three honest caveats. Rate limit and monthly allowance are separate ceilings — you can be well under 110 req/s and still exhaust Helius's 1M credits in a day of steady traffic. A sustained 110 req/s burns roughly 285M calls a month, far past every allowance here; the stack is sized for bursts and development traffic, not a constant load. And the proxy's own health probes draw on the same allowances, around the clock. At the probe interval used below they take about 1.5M of the 13.3M reads; at a 2-second interval they would take 11M of them before you sent a single request (see why it works).
Writes are the real constraint. Helius allows 1 sendTransaction/s on free, and the public endpoint
is not somewhere to land transactions. If you are writing more than a couple of transactions a
second, a paid provider is the answer, not more free keys.
Config¶
[health]
interval_ms = 30000 # every probe is 2 billed getSlot calls per key; see "Why it works"
window_secs = 30
circuit_open_failures = 3 # hard failures in a row; a 429 never opens a circuit
circuit_error_threshold = 0.4
circuit_cooldown_secs = 2 # a failed key gets back on trial at the first probe after this
[routing]
strategy = "weighted_random" # spread load across all providers
max_retries = 8 # try all nine before giving up
[[providers]]
name = "alchemy"
url = "https://solana-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
weight = 5 # weights track capacity: 25 req/s is the biggest share
max_rps = 25
[[providers]]
name = "chainstack"
url = "${CHAINSTACK_URL}" # copy your node endpoint from the Chainstack console
weight = 5
max_rps = 25
[[providers]]
name = "onfinality"
url = "${ONFINALITY_URL}" # copy your endpoint from the OnFinality dashboard
weight = 4
max_rps = 20 # 40 RU/s at 2 RU per call
[[providers]]
name = "quicknode"
url = "https://your-endpoint.solana-mainnet.quiknode.pro/${QUICKNODE_API_KEY}/"
weight = 3
max_rps = 15
[[providers]]
name = "helius"
url = "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}"
weight = 2
max_rps = 10
[[providers]]
name = "solana-foundation"
url = "https://api.mainnet-beta.solana.com"
weight = 2
max_rps = 10
[[providers]]
name = "publicnode"
url = "https://solana-rpc.publicnode.com"
weight = 2
max_rps = 10 # no published limit — start conservative and raise it on evidence
history = "recent" # keeps about a week of history; see "Not every free endpoint keeps old history"
[[providers]]
name = "drpc"
url = "${DRPC_URL}" # copy your endpoint from the dRPC dashboard
weight = 2
max_rps = 10 # no published free-tier limit, and it runs on the public pool — stay conservative
[[providers]]
name = "solana-vibe-station"
url = "https://free.rpc.solanavibestation.com/?api_key=${SVS_API_KEY}"
weight = 1
max_rps = 5
history = "recent" # ~11 h of getSignaturesForAddress, and a gap in getTransaction
export ALCHEMY_API_KEY=...
export QUICKNODE_API_KEY=...
export HELIUS_API_KEY=...
export CHAINSTACK_URL=... # full endpoint URL, key included
export ONFINALITY_URL=...
export DRPC_URL=...
export SVS_API_KEY=...
rpc-plane -c free-tier.toml run
A bundled version ships as examples/free-tier.toml.
Why it works¶
Weights track capacity, not provider count. Equal weights send Helius the same share as
Alchemy, so Helius hits its 10 req/s cap while Alchemy sits idle at 40% utilisation — and the stack
sheds load long before it needs to. Setting weight in proportion to each cap (5/5/4/3/2/2/2/2/1 for
25/25/20/15/10/10/10/10/5) keeps every provider at roughly the same percentage of its own limit.
weighted_random over failover_ordered. failover_ordered sends everything to the first
provider and moves down the list only when that one fails or reaches its cap. That burns one monthly
allowance at a time. weighted_random spreads from the first request.
max_rps makes it proactive. A 429 doesn't open a circuit, since the key is healthy, only
capped. It demotes the key's score, so weighted_random sends it less, but only after the key has
already refused requests. A max_rps cap sheds
load before the 429s start. Set each one to the limit the plan actually publishes. It is a
load-shedding hint, not a hard throttle: if every key is momentarily at its cap the proxy forwards
anyway rather than dropping the request.
interval_ms = 30000, because the probe is billed too. Every interval the proxy probes each
provider with two getSlot calls, one each at processed and finalized (the default
probe_commitments). They are ordinary billed calls, they
don't draw from max_rps, and they run whether or not you send any traffic. At a 2-second interval
that is 2.6M calls per key per month, enough to use up several of these allowances on its own:
| Free allowance | getSlot costs |
Probes at 2 s | Probes at 30 s |
|---|---|---|---|
| Helius, 1M credits/month | 1 credit | gone in 12 days | 17% |
| QuickNode, 10M-credit trial (once) | 30 credits | gone in 4 days | gone in 58 days |
| Alchemy, 30M CU/month | 20 CU | gone in 17 days | 12% |
| Chainstack, 3M RU/month | 1 RU | 86% | 6% |
| OnFinality, 400K RU/day | 2 RU | 43% | 3% |
| dRPC, 210M CU/30 days | 20 CU | 25% | 1.6% |
That assumes the proxy runs all month. Solana Vibe Station, the Solana Foundation and PublicNode meter nothing, so there the probe only costs rate, 0.07 req/s per key at 30 seconds.
What a longer interval gives up is how fresh the health readings are. Slot drift and latency come
from the probe, so a key that falls behind is noticed within 30 seconds rather than 2. Failures are
still noticed at once: live requests feed the circuit breaker too, and with max_retries covering
every leg a failed request is retried elsewhere. For light traffic, 60000 halves the probe cost
again.
circuit_cooldown_secs = 2. A circuit opens only on hard failures (errors and timeouts), never
on a 429. Once the cooldown has passed, the next probe puts the key back in rotation on trial, and the
first live success closes the circuit. The 30-second default would add up to another 30 seconds to
that.
max_retries = 8. With nine providers, N - 1 means every one is tried before the proxy gives
up. Drop it to match if you leave any leg out — the no-signup and unpublished-limit legs (PublicNode,
dRPC) are the easiest to drop first.
The per-method limits are tighter than the headline¶
This is the part that catches people. Providers publish one number in the marketing table and several smaller ones underneath:
| Headline | sendTransaction |
DAS | getProgramAccounts |
|
|---|---|---|---|---|
| Helius free | 10 req/s | 1/s | 2/s | 5/s |
| Solana Foundation | ~10 req/s | — | — | 4/s for any single method |
| Chainstack free | 25 req/s | not published separately | — | — |
| Alchemy free | 25 req/s | not published separately | — | — |
| QuickNode trial | 15 req/s | not published separately | — | — |
| OnFinality free | 20 calls/s | not published separately | — | — |
| Solana Vibe Station free | 5 req/s | 1/s | not served | not published for Free (2/s on Lite) |
Chainstack publishes its per-method caps on a different axis — not by category but by named method:
getBlock 400 RPS, getBlockTime / getBlocks / getBlocksWithLimit 500 RPS,
getTokenAccountsByOwner 80 RPS in most regions, and getSupply at 2 RPS on paid plans only, so
on the free Developer tier getSupply is not available at all. All of those sit above the free
tier's 25 req/s except getSupply, so in practice the plan limit binds first — but if you route
getSupply through Chainstack on the free tier it will simply fail, and that is worth an allowlist.
max_rps is per provider, not per method — all methods draw from one bucket — so max_rps = 10 on
Helius lets you spend the entire allowance on writes and take 429s at a tenth of the cap.
The fix uses what already ships. max_rps is per provider entry, and only name has to be
unique, so register the same key twice:
# Writes get their own 1 rps bucket.
[[providers]]
name = "helius-writes"
url = "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}"
methods = ["sendTransaction"]
weight = 1
max_rps = 1
# Everything else uses the general limit.
[[providers]]
name = "helius-reads"
url = "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}"
weight = 2
max_rps = 10
Two independent buckets: writes cannot eat the read budget, and
rpc_plane_rate_limited_total{provider="helius-writes"} tells you exactly which limit is binding.
The write entry excludes getSlot, so it skips the health probe and is scored from live request
outcomes instead — see submission-only providers and
working around a per-method limit.
Worth doing for any provider whose write cap you actually care about. It is the difference between 1 write/s working reliably and 1 write/s working until your read traffic spikes.
Keep the history reads off the small tiers¶
The monthly allowances above assume standard reads. History calls do not cost the same:
| Standard read | getBlock / getTransaction |
|
|---|---|---|
| Helius | 1 credit | 10 credits |
| Alchemy | 10 CU | 40 CU |
| QuickNode | 30 credits | 30 credits (no premium) |
A getBlock-heavy workload drains Helius's 1M credits ten times faster than the headline figure
suggests. If you are backfilling history on free tiers, send those calls to QuickNode — it charges
no archival premium — using a methods allowlist, and let the
others take the account reads. See the pricing reference for the full
tables.
Not every free endpoint keeps old history¶
Cost is one problem with history on free endpoints. Depth is the other: some keep only the last few
days, and they don't return an error for anything older. Checked on 2026-10-27, PublicNode answered
getTransaction with null for a transaction 7 days old, where the Solana Foundation endpoint still
served one from 180 days back. Its getSignaturesForAddress returned 87 of an address's latest 1000
signatures, also without an error.
Behind a proxy that makes a pool with one shallow leg unreliable for history. Under
weighted_random, every lookup for an older transaction that lands on the shallow leg comes back as
"transaction not found". Under parallel_race it is worse: the null is cheap to produce, so the
shallow leg is usually the fastest.
Solana Vibe Station's free key goes further back, but it fails in two ways that don't return an
error either. Checked on 2026-11-06, its getSignaturesForAddress covered only about the last 11
hours: 236 of an address's latest 1000 signatures. And getTransaction, which otherwise served
transactions back to October 2024, returned null for 49 of 76 sampled transactions from 31 August
to 21 October 2026. The details are on its setup page.
That is what history = "recent" on the PublicNode and Solana Vibe Station entries above is for:
- Its
nullor error answer togetTransactionorgetBlockfails over to another provider, so a lookup outside its window costs one extra round trip instead of a wrong answer. getSignaturesForAddressis never sent to it, since a truncated list gives nothing to fail over on.- Misses show up as
rpc_plane_requests_total{status="miss"}and don't count against its health.
Check any other free key the same way before trusting it with history: call getTransaction for a
signature a few months old. null, where another provider returns the transaction, means it belongs
in recent. See history lookups for the full behaviour.
When to upgrade¶
This is a development, side-project and non-critical-traffic setup. Free endpoints are rate limited and carry no SLA.
The signal to move is not usually throughput — it is one of these:
- You need more than ~1 write/second. Helius and Solana Vibe Station both cap
sendTransactionat 1/s on their free tiers, and neither public endpoint is somewhere to land transactions. - You are exhausting a monthly allowance before the month ends.
- QuickNode's trial credits ran out and the stack quietly dropped to ~95 req/s.
- You need a rate limit you can design against — neither no-signup endpoint publishes one.
- You need someone to call when it breaks.
At that point add one paid provider as primary and keep the free stack as failover with
failover_ordered — the free keys cost nothing to leave in place,
and they are a genuinely useful backstop when the paid provider has a bad day.