Solana's 400ms block time is fast on paper. In practice, most apps see end-to-end latency of 1.5–3 seconds because of how the request travels through the network. This post explains why, and what you can actually do about it.
The Real Latency Stack
When you call sendTransaction, here's what happens between your code and a confirmed slot:
- Client → RPC — Your HTTPS request crosses the public internet
- RPC → Network — The RPC node submits the transaction into the Solana network
- Block production — A validator includes it in a block
- Block → Confirmation — The cluster votes and confirms
Each layer adds latency. The first two are where most apps lose 80% of their time, and they're also the layers you can actually optimise.
Why Most Setups Are Slow
Three things kill latency for most teams.
1. RPC Distance
If your client and your RPC are far apart on the public internet, every transaction pays a long round-trip. There is no software fix for the speed of light. Use an RPC provider with infrastructure close to your traffic — or one that handles routing for you so you don't have to think about it.
2. Re-using TCP Connections Wrong
Every transaction creates a new HTTPS connection? You're paying ~100ms of TLS handshake on every single send. Enable HTTP keepalive in your client and reuse one connection across thousands of sends.
For Node.js (web3.js v1), use an undici agent to reuse connections:
import { Connection } from "@solana/web3.js";
import { Agent, fetch as undiciFetch } from "undici";
// Global keep-alive agent, reuses TCP/TLS connections across calls
const agent = new Agent({
keepAliveTimeout: 30_000,
keepAliveMaxTimeout: 600_000,
});
const connection = new Connection("https://bolttx.io/?api-key=YOUR_KEY", {
commitment: "processed",
fetch: (url, init) => undiciFetch(url, { ...init, dispatcher: agent }),
});
In a browser, keep-alive is handled by the browser itself — you don't need to configure it. There's a fuller treatment of HTTP-layer tuning in our keep-alive and connection-pooling guide.
3. skipPreflight Misuse
// SLOW — preflight does a full simulation before sending
await connection.sendTransaction(tx, signers);
// FAST — skip the simulation, save ~100ms
await connection.sendTransaction(tx, signers, {
skipPreflight: true,
maxRetries: 0,
});
If you trust your transaction (you built it, you signed it, you know it'll succeed), skipping preflight saves ~100ms per send. Just handle errors yourself. The full trade-off is covered in our skipPreflight guide.
How to Measure Latency Properly
Before you optimise, you need real numbers — not the marketing latency on a cold endpoint.
Don't trust averages. Average latency hides the tail; for trading workloads the tail is what kills you. Track P50, P95, and P99 separately. A bot whose average is 400ms but whose P95 is 2.5s will still miss most of its opportunities.
Don't measure single calls. One ping doesn't tell you anything. Send a sustained workload (a few hundred transactions over an hour, ideally during congestion) and look at the distribution.
Measure end-to-end, not just HTTP round-trip. What you care about is "from sendTransaction to landed on chain," not just "how fast did the RPC accept my request." Two different numbers.
A simple harness:
const start = Date.now();
const sig = await connection.sendTransaction(tx, signers, {
skipPreflight: true,
maxRetries: 0,
});
const submittedMs = Date.now() - start;
const status = await connection.confirmTransaction(
{ signature: sig, blockhash, lastValidBlockHeight },
"confirmed"
);
const totalMs = Date.now() - start;
logger.info({ sig, submittedMs, totalMs, slot: status.context.slot });
Log every transaction with timing, then compute percentiles offline. The methodology is detailed in our RPC benchmarking guide.
Tip and Priority Fee: The Two Levers That Actually Land Transactions
Latency optimisation gets you halfway. The other half is landing under congestion, which depends on two separate-but-related fees:
Priority fee is the on-chain gas fee at the Solana protocol level. Setting it meaningfully above the current network average pushes your transaction toward the front of the inclusion queue. Setting it at zero in a busy network is a near-guaranteed way to expire blockhashes.
BoltTx tip is the small fee you pay BoltTx in exchange for submission-side priority — the more you tip, the higher the priority your transaction gets on our submission infrastructure, and the faster it lands. You only pay when the transaction actually lands; failed sends cost nothing on BoltTx's side.
These two are independent. Tune both together for the fastest landing:
- A high priority fee with no BoltTx tip = front of the on-chain inclusion queue, but standard submission
- A high BoltTx tip with no priority fee = priority submission, but no on-chain queue advantage
- Both meaningfully above baseline = best of both layers
For a deeper treatment of how to size priority fees by expected profit instead of brute-forcing the maximum, see our priority fees guide.
What BoltTx Looks Like in Practice
For a typical Raydium swap from cross-region clients, here's the kind of profile we consistently see in production:
| Metric | What we see |
|---|---|
| Average confirm | Sub-500 ms |
| P50 (median) | Sub-400 ms |
| P95 | Under 1 second |
| Long tail (>1s) | Minimal |
Numbers vary by client geography, transaction complexity, and network conditions. We recommend running your own benchmarks against your real traffic profile — that's the only number that matters for your use case.
The biggest gains come from:
- Single global endpoint with internal smart routing — no manual region picking, no infrastructure decisions for your team
- Dedicated SWQoS + prioritised connections, included in every plan — your transactions land even under heavy network load
- Native Anti-MEV so transactions aren't front-run before they're included. Why this matters in practice is covered in our Anti-MEV guide.
What to Do This Week
If you're shipping a Solana app and care about latency, do these in order:
- Measure your current P95, not just average. Average hides the tail.
- Pick an RPC with infrastructure close to your client — or one that handles routing internally. See how trading bots evaluate RPCs for the criteria that matter.
- Enable keepalive on your HTTP client.
- Try
skipPreflight: truefor the hot path. - Set
maxRetries: 0and handle retries explicitly. The full sendTransaction playbook is in our best-practices guide. - Tune both priority fee and tip together. Neither alone is enough under real congestion.
Try BoltTx
If you want sub-second confirmation without thinking about any of this, sign up for BoltTx and swap one URL in your existing code:
const connection = new Connection(
"https://bolttx.io/?api-key=YOUR_API_KEY",
"processed"
);
That's it. Your existing sendTransaction calls now route through BoltTx — single global endpoint, internal smart routing, sub-second confirmation, native Anti-MEV. No region selection, no infrastructure decisions.