Skip to content

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.