Solana Priority Fees and Compute Units, Explained

Here's a detail that surprises a lot of people the first time they build on Solana: the priority fee you pay is based on the compute you ask for, not the compute you actually use. Leave the default limit in place and you can end up paying for headroom your transaction never touches. Solana priority fees and compute units are the two dials behind most "why is my transaction stuck" and "why did that cost more than I expected" questions. I'm going to walk through how they actually work, straight from the official docs, what a sane setup looks like, and where the limits are. Sources are linked so you can check me.
What do you actually pay to send a Solana transaction?
Per Solana's fee documentation, every transaction fee has two parts: a base fee and an optional prioritization fee (everyone calls it the priority fee).
- Base fee. 5,000 lamports per signature (a lamport is the smallest unit of SOL). Half is burned and half goes to the validator that produces the block.
- Priority fee. Optional, and it raises the chance that the current leader (the validator producing blocks right now) schedules your transaction ahead of competing ones. Since SIMD-0096, 100% of it goes to the validator and none is burned, per the fee structure page.
The part people forget: the fee is taken from the fee payer before execution, and it's charged even if the transaction fails. A failed swap isn't free. That's a big reason to get the next part right.
What is a compute unit?
A compute unit (CU) is how Solana's runtime meters work. Every operation, whether it's arithmetic, memory access or a syscall, costs a fixed number of CUs. Each transaction carries a compute unit limit, which is the most it's allowed to burn through.
If you don't set one, the compute budget docs say the default is calculated from your instructions: 200,000 CUs for each instruction that calls a deployed program, and 3,000 for each builtin one like a plain System Program transfer. The whole transaction is capped at 1,400,000 CUs.
Two settings control all of this, both instructions in the Compute Budget Program:
SetComputeUnitLimitsets the maximum CUs the transaction may consume.SetComputeUnitPricesets how much you'll pay per CU, in micro-lamports (one millionth of a lamport).
How is the priority fee calculated?
The formula from the docs is short: priority fee = compute unit price × compute unit limit ÷ 1,000,000, rounded up, in lamports. The limit in that formula is the one you requested, which is exactly why the opening detail matters.
A worked example (hypothetical numbers)
Say your transaction calls two programs and you never set a limit. The default gives you 2 × 200,000 = 400,000 CUs. Now say simulation shows it really only uses 120,000. At a made-up price of 10,000 micro-lamports per CU:
- Default limit: 10,000 × 400,000 ÷ 1,000,000 = 4,000 lamports of priority fee.
- Simulated limit plus a 10% margin (132,000 CUs): 10,000 × 132,000 ÷ 1,000,000 = 1,320 lamports.
Same transaction, same price per CU, roughly a third of the priority fee. These numbers are only there to show the math, not to suggest what you should pay. The real price moves with demand.
Why a tighter limit can help you land, too
Cost isn't the only reason to request what you need. The docs describe the priority fee as a way to raise scheduling priority, and the knob that does that is the price per CU. Since what you pay is price × limit, padding the limit makes every price bump more expensive. For the same total spend, a tighter limit lets you offer a higher price per CU.
The flip side is real. Set the limit too low and the transaction runs out of compute and fails, and you still pay the fee. That's why the docs recommend simulating first and adding a margin instead of guessing.
How to set compute and priority fees without guessing
Here's the baseline I'd want in anything that sends transactions, whether it's a bot, a dapp or a script:
- Simulate, then size. Run the transaction through
simulateTransaction, read the CUs it consumed, and set the limit to that plus about 10%, as the compute budget docs suggest. - Price from recent data. The
getRecentPrioritizationFeesRPC method returns recent fee samples in micro-lamports per CU. Pass the writable accounts your transaction touches (up to 128) and the samples reflect transactions that locked those same accounts. - Cap what you'll pay. Set a max price your app won't go above, so a busy hour can't quietly drain a wallet through fees.
- Use a fresh blockhash. Per the confirmation and expiration guide, a blockhash stays valid for 150 slots, which works out to roughly 60 to 90 seconds. Fetch it right before signing with
getLatestBlockhash, usually atconfirmedcommitment, and tracklastValidBlockHeightso you know when a retry needs a new one. - Show the user the fee. If people are signing, tell them what the priority fee will be before they approve. Surprise fees kill trust fast.
What priority fees won't fix
A priority fee raises your chances of being scheduled. It doesn't guarantee inclusion, and it does nothing if the transaction itself is broken.
- Program errors still fail. A bad instruction, a slippage check that trips or a missing account fails no matter what you bid, and the fee is still charged.
- Hot accounts are contested. When lots of transactions want to write to the same account, you're competing with all of them. The account filter in the fee RPC exists for that reason.
- Fee samples look backward. Recent fees describe the last stretch of blocks (the docs say a node's fee cache holds up to 150), not the next one.
- The format is changing. The docs describe a newer v1 transaction format where Compute Budget instructions are ignored and the priority fee is set as a flat lamport total in the message config instead of a per-CU price. The priority fee cookbook notes that
@solana/kituses separate setters for each format. Check which format your stack sends before you copy anyone's fee code, mine included.
One more honest limit: everything here comes from the official docs, not from benchmarks I've run. How much a given price helps at a given moment depends on network conditions, which no doc can tell you ahead of time.
Why this matters beyond developers
If you only trade and never write code, this still affects you. Every bot, wallet and trading app you use is making these choices for you. Some set sensible limits and show you the fee. Others leave defaults in place or let fees climb with no cap. For the bigger picture on how the network itself is doing, see my read on Solana's network health.
A good test for any tool: can it tell you what it paid in fees on a trade, and does it let you cap that? If it can't, you're trusting it blind. The same goes for checking where your money actually went, which is what reading a wallet on-chain is for. More plain-words walkthroughs live in the guides, and the Labs page shows what I'm building.
The takeaway
Solana priority fees aren't a magic speed button. They're a price per compute unit, multiplied by a limit you choose. Simulate to find what your transaction really uses, set the limit just above it, price from recent fees on the accounts you touch, cap the max and always grab a fresh blockhash. Do that and you stop paying for compute you never use, and when a transaction fails you'll at least know why. If you've built on Solana, what's the fee mistake that cost you the most to learn? 👨💻
Still building. Still here. 🫡
Keep reading: all articles · DarkGeneral Labs · live crypto news · latest posts on X.


