Jito bundles versus staked connections
Jito bundles buy atomic, ordered execution and a shot at the top of a block. Staked connections buy fast, reliable delivery to the leader. They solve different problems, they are not mutually exclusive, and picking the wrong one costs you either money or fills.
- Bundles buy atomic, ordered execution across up to five transactions. Nothing else on Solana gives you that.
- Staked connections buy admission: the leader reading your packets during contention.
- They are not competing products. They operate at different layers and compose.
- If you need atomicity, only a bundle will do. If you need delivery, a bundle is not the tool.
This comparison is usually framed as a choice, and that framing is wrong. Jito bundles and staked connections answer different questions, and the confusion between them leads people to buy the wrong thing and then conclude it did not work.
We sell one of these, so read the disclosure at the end and weigh the rest accordingly. I have tried to write the version I would want to read if I were choosing.
They solve different problems#
| Jito bundle | Staked connection | |
|---|---|---|
| Question answered | Will these execute together, in order? | Will the leader read my packet? |
| Layer | Block construction | Network admission |
| Atomicity | Yes, up to five transactions | No |
| Ordering guarantee | Yes, within the bundle | No |
| You pay when | Only if it lands | Per submission |
| Works with every leader | Only Jito-enabled leaders | Yes |
| Failure mode | Silently loses the auction | Delivered, may still not land |
Read the first row twice. “Will these execute together” and “will my packet be read” are not competing answers to one question, they are answers to two.
What a bundle actually gives you#
A bundle is up to five transactions submitted to a block engine, which runs an auction and forwards the winners to a Jito-enabled leader for inclusion at the top of the block. Within a bundle, execution is atomic and ordered.
1import { Connection, VersionedTransaction, SystemProgram, PublicKey } from "@solana/web3.js";2import bs58 from "bs58";34/**5 * A bundle is an ordered list of up to five transactions that execute6 * atomically and in the order given, or not at all.7 *8 * The tip is a plain SOL transfer to a tip account, included as an instruction9 * inside one of the bundled transactions. It is what you bid for inclusion, and10 * unlike a priority fee it is only paid if the bundle actually lands.11 */12const TIP_ACCOUNTS = [13 "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",14 "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe",15 // ...rotate across the published set so you do not create contention on one16];1718export function tipInstruction(from: PublicKey, lamports: number) {19 const to = new PublicKey(TIP_ACCOUNTS[Math.floor(Math.random() * TIP_ACCOUNTS.length)]);20 return SystemProgram.transfer({ fromPubkey: from, toPubkey: to, lamports });21}2223export async function sendBundle(blockEngineUrl: string, txs: VersionedTransaction[]) {24 if (txs.length > 5) throw new Error("a bundle is at most five transactions");2526 const res = await fetch(`${blockEngineUrl}/api/v1/bundles`, {27 method: "POST",28 headers: { "Content-Type": "application/json" },29 body: JSON.stringify({30 jsonrpc: "2.0",31 id: 1,32 method: "sendBundle",33 params: [txs.map((t) => bs58.encode(t.serialize()))],34 }),35 signal: AbortSignal.timeout(5_000),36 });3738 const body = await res.json();39 if (body.error) throw new Error(`bundle rejected: ${body.error.message}`);4041 // A bundle id is NOT a landing confirmation. It means the block engine42 // accepted your submission into the auction. You still have to check.43 return body.result as string;44}
The genuinely unique property is atomicity, and it is not replaceable.
1/**2 * The case bundles exist for: two operations that are only safe together.3 *4 * A liquidation that borrows, liquidates and repays is worthless if the first5 * two land and the third does not. Sequenced as separate transactions, another6 * actor can interleave between them. Bundled, either the whole sequence7 * executes in order or none of it does.8 *9 * There is no way to build this out of independent transactions. It is not a10 * latency optimisation, it is a correctness property, and if you need it then11 * nothing else on this page substitutes for it.12 */13const bundle = [14 buildFlashBorrow(amount), // 115 buildLiquidation(position), // 216 buildRepayWithTip(amount, tip) // 3, carries the tip17];1819// All three, in this order, in one block. Or nothing.20const bundleId = await sendBundle(BLOCK_ENGINE, bundle);
You cannot build that out of independent transactions. Between transaction two and transaction three, anyone can act. If your strategy has a window in which a partial execution is unsafe, a bundle is not an optimisation, it is the requirement.
The limits worth knowing
- Not every leader runs Jito. When the current leader does not, bundles have nowhere to go for that slot. Coverage is high but it is not universal, and the gaps are invisible to you.
- The auction is an auction. Losing is the normal case, not an error, and it produces no failure at submission time.
- A bundle id is not a confirmation. It means the block engine accepted your entry.
- Five transactions, and the whole bundle must fit the block.
1/**2 * Confirm a bundle landed. The bundle id is a receipt for the auction, not3 * for the chain.4 *5 * Bundles fail silently and often: you lost the auction, the simulation failed6 * at the block engine, or the leader for that slot was not running Jito. None7 * of those produce an error at submission time.8 */9export async function bundleLanded(blockEngineUrl: string, bundleId: string) {10 const res = await fetch(blockEngineUrl, {11 method: "POST",12 headers: { "Content-Type": "application/json" },13 body: JSON.stringify({14 jsonrpc: "2.0", id: 1,15 method: "getBundleStatuses",16 params: [[bundleId]],17 }),18 });1920 const { result } = await res.json();21 const status = result?.value?.[0];2223 if (!status) return { landed: false, reason: "unknown, likely lost the auction" };24 if (status.confirmation_status) return { landed: true, slot: status.slot };25 return { landed: false, reason: status.err ?? "not included" };26}2728// Budget for this. A meaningful share of bundles do not land, and the ones29// that do not are invisible unless you check.
What a staked connection gives you#
A staked connection addresses an earlier question. Before ordering matters, before block construction matters, the leader has to accept the connection carrying your transaction and read the stream.
Capacity for that is allocated in proportion to stake. Unstaked senders contend for a small shared remainder, which during congestion is where transactions quietly evaporate. The mechanism is covered in stake-weighted QoS explained.
What it does not give you:
- No atomicity. Each transaction stands alone.
- No ordering guarantee against anyone else.
- No guarantee of inclusion. Delivery is not the same as landing.
It is a narrower promise, and being honest about how narrow is the whole point of this page.
Tips are not priority fees#
Three payment mechanisms get conflated constantly. They are genuinely different.
| Base fee | Priority fee | Jito tip | |
|---|---|---|---|
| Paid to | Burned and validator | Validator | Tip account, shared with validators |
| Denominated in | Lamports per signature | Micro-lamports per CU | Lamports, flat |
| Buys | Nothing, mandatory | Scheduling position | Bundle auction position |
| Paid when you lose | Yes, if it lands | Yes, if it lands | No |
| Set by | The protocol | ComputeBudget instruction | A transfer instruction |
The fourth row is the economically interesting one. A priority fee is spent whether or not you win the race you were bidding for. A tip is only paid if the bundle lands. That changes optimal bidding behaviour: you can bid more aggressively on a tip because losing costs nothing, which is also why tip auctions clear high.
Choosing between them#
You need a bundle when:
- A partial execution of your sequence is unsafe. Liquidations, flash loans, atomic arbitrage.
- You need to be adjacent to a specific transaction, before or after it.
- You need ordering across several transactions that you control.
- Paying only on success materially changes your economics.
You need staked delivery when:
- Your transactions are individually valid and simply are not arriving.
- Your losses do not correlate with fee, blockhash freshness or compute.
- You are sending continuously and need consistency rather than a shot at a specific block.
- You need to reach every leader, including those not running Jito.
Neither is your problem when:
- Your blockhash handling is loose. Fix that first; it is free.
- Your fee is priced off a constant rather than live per-account data.
- You are requesting 1.4 million compute units by default.
- You are polling an RPC to detect the events you react to.
That third list is not a rhetorical flourish. It is the most common actual answer, and both of the products on this page are more expensive than fixing it. Work through the diagnostic first.
Using both#
They compose, because they act at different layers. A realistic setup for a trading operation:
- Bundles for anything requiring atomicity or adjacency, where losing the auction is an acceptable outcome because you pay nothing for it.
- Staked delivery for the continuous flow of ordinary transactions, where you want consistent admission across every leader.
A common pattern is to attempt a bundle and fall back to a direct send when the auction is lost, accepting that the fallback has no atomicity. Whether that fallback is safe is a property of your strategy, not of the infrastructure, and it is worth thinking through carefully rather than assuming.
The cost comparison nobody does#
Comparing a per-send fee against a tip is comparing different things, and doing it properly needs expected values rather than sticker prices.
| Bundle | Staked delivery | |
|---|---|---|
| Charged | Only on success | Per accepted submission |
| Cost of losing | Zero | The per-send price |
| Cost scales with | Competition for that block | Volume |
| Predictability | Low, auctions are volatile | High, a flat price |
Which gives a rough rule:
- High value, low frequency, atomicity required. Bundles. Paying only on success is worth a great deal when each attempt is individually valuable.
- Lower value, high frequency, no atomicity required. Staked delivery. Predictable per-send cost, and you are not repeatedly bidding into an auction you will usually lose.
For a bot sending thousands of ordinary transactions a day, tip auctions become an expensive and unpredictable way to buy something you did not need. For a liquidator taking a handful of high-value shots, a flat per-send price is noise and atomicity is everything.
Where we stand#
We run a relay with staked connections. That is one of the two things on this page, so weigh the following accordingly.
Three things I would say if I had no stake in it:
- If you need atomicity, only a bundle will do. There is no substitute, and nothing we sell gets close. Do not let anyone talk you out of it on latency grounds.
- Most people asking this question have neither problem. They have a stale blockhash, a constant fee, or a polling loop. Both products are more expensive than fixing those, and neither will help until they are fixed.
- They are not substitutes. Anyone telling you that one replaces the other is selling something, including us if we ever say it.