HTTP/3 for Solana RPC — and why it probably isn't your bottleneck¶
Every Solana SDK speaks HTTP/1.1. @solana/web3.js posts JSON over fetch, the Rust client uses
reqwest defaults, and nothing in the ecosystem negotiates QUIC. Meanwhile several RPC providers
serve HTTP/3 and have for a while — checked 2026-09-06, Helius, Triton One, dRPC and the Solana
Foundation's public endpoint all advertise Alt-Svc: h3; Alchemy and Chainstack do not.
A proxy is a natural place to close that gap: your app keeps talking HTTP/1.1 to localhost, and
the proxy speaks whatever the provider supports upstream. RPC Plane supports exactly that, per
provider, with http3 = true.
Most deployments should leave it off. This post is mostly about why.
What QUIC actually gives you¶
Two things, and both are about the network being bad.
A 1-RTT handshake instead of ~3. TCP needs a SYN/SYN-ACK round trip before TLS can start, then TLS needs its own. QUIC folds transport and crypto setup together and establishes in roughly one round trip. On a fresh connection to a provider 80 ms away, that is the difference between ~240 ms and ~80 ms before your first byte moves.
No transport-level head-of-line blocking. HTTP/2 multiplexes many requests over one TCP connection. TCP guarantees ordered delivery, so one lost packet stalls every stream on that connection until it is retransmitted — even the ones whose data already arrived. QUIC's streams are independent: a loss on one does not block the others.
Both of those are real. Neither of them is doing anything for you on a warm connection over a clean datacenter link.
Why it usually buys nothing¶
The handshake win is a setup cost, and a proxy's whole job is to not pay setup costs. RPC Plane holds a pooled, warm connection to each provider and — under default config — the health probe keeps at least one alive per provider continuously. If you never re-handshake, a cheaper handshake is worth nothing.
The head-of-line-blocking win needs packet loss. On a datacenter path with negligible loss, HTTP/2 never stalls, so there is nothing for QUIC to avoid.
What is left is the cost side: QUIC runs in userspace, where TCP runs in the kernel with decades of offload behind it. On a clean fast path, HTTP/3 can measurably cost more CPU than HTTP/2 for the same throughput.
So the honest summary is: on the deployment this proxy is designed for — colocated sidecar, warm pool, well-connected providers — expect nothing worth chasing, and possibly a small regression from the userspace CPU cost.
That is a claim about a datacenter path, where the network floor is a fraction of a millisecond and there is nowhere for TCP's overhead to hide. Measured further down, on a residential path with a 27 ms floor, warm HTTP/3 did come out about 2 ms ahead — small, consistent, and free, but still not a reason to change anything.
Where it does earn its keep¶
Two shapes, both of which reintroduce the setup cost QUIC is good at eliminating:
- Connection churn. Cold starts, failover storms, autoscaling, or providers that aggressively drop idle connections. If you are repeatedly re-establishing, the ~3-RTT-to-~1-RTT change is large and it applies to every reconnect — measured below at one full round trip saved per connection, a third off the request.
- High-latency or lossy links. Cross-region hops, congested transit, or anything running over a residential/last-mile connection. Here loss is not hypothetical and head-of-line blocking is a genuine tail-latency source.
If you are running the proxy on a laptop against providers on another continent, turn it on. If you are running it next to your app in the same region as your providers, do not.
The sharp edge: there is no fallback¶
This is the part worth reading twice before enabling it.
RPC Plane's HTTP/3 client is built with QUIC prior knowledge — it speaks only HTTP/3 to a
provider marked http3 = true. There is no negotiation and no silent downgrade to HTTP/2.
If the provider does not serve QUIC, or a middlebox on the path blocks UDP/443 — which plenty of corporate networks and some cloud egress configurations do — then every request to that provider fails. It fails over to the next provider in your fleet rather than erroring outright, so the symptom is not an outage; it is one provider silently receiving no traffic, forever, for a reason that will not show up as a config error.
[[providers]]
name = "some-provider"
url = "https://..."
http3 = true # only after you have confirmed this endpoint serves QUIC
Confirm QUIC support per endpoint before enabling it, and check /health and
rpc_plane_* metrics afterwards to see that the provider is actually being used. Treat the whole
feature as experimental: it depends on a pinned reqwest built with an unstable HTTP/3 feature.
What this actually measures out to¶
Measured 2026-09-06, from a residential connection in Bangkok (National Telecom) to a Triton One pool endpoint on its Singapore edge. Path RTT 27.30 ms, 0.29 ms mdev. Four arms, 800 requests each at 40 req/s, run twice; 3,200 measured requests, zero errors.
| Arm | p50 | p95 | p99 |
|---|---|---|---|
| TCP+TLS, warm pool | 28.72 ms | 39.50 ms | 72.99 ms |
| HTTP/3, warm pool | 26.85 ms | 36.04 ms | 61.78 ms |
| TCP+TLS, cold connection | 89.97 ms | 106.12 ms | 143.73 ms |
| HTTP/3, cold connection | 61.76 ms | 73.17 ms | 107.88 ms |
The cold saving is one round trip. 28.21 ms saved against a 27.30 ms path RTT — 1.03 RTT. That is the handshake story from the top of this post, and the arithmetic closes: TCP+TLS needs about three round trips before payload moves, QUIC needs one, the request costs one more.
Warm HTTP/3 is sitting on the network floor. 26.85 ms against a 27.30 ms RTT is 0.98 RTT — a request cannot beat the speed of the path. TCP's 28.72 ms is a couple of milliseconds above it. So the warm gain is real, and consistent across both passes at p50, p95 and p99 — but read it as "QUIC reaches the floor and TCP is slightly above it", not as a portable 6.5%.
That is the whole argument of this post in two rows. On a connection you are re-establishing, HTTP/3 is about a third faster. On one you are holding open, it is worth two milliseconds. A proxy's job is to hold connections open, which is exactly why the answer for a colocated sidecar is still "leave it off".
What this does not show¶
- Nothing about packet loss. This path was clean: 0.29 ms mdev, zero errors in 3,200 requests. QUIC's other advantage — no transport head-of-line blocking when a packet drops — never came into play. On a congested or lossy link it should widen the warm gap, and nothing here measures that.
- One origin, one provider, one region. Bangkok to Singapore at 27 ms. On a longer path the absolute cold saving grows with the RTT; the percentages should hold roughly.
- Latency, not throughput. Eight concurrent connections, paced at 40 req/s. This is not a saturation test.
Related¶
- Configuration → When to enable HTTP/3
- Architecture — client rebuild behaviour when
http3changes - FAQ — measured latency overhead and load-test conditions