Transaction fees and compute units
A Solana transaction pays for two separate things. It pays a small fixed amount for the right to land in a block at all, and an optional extra amount for the leader to schedule it ahead of competing transactions. The first is the base fee. The second is the priority fee. Understanding which one is which, and why both exist, is what makes the rest of the cost story stop feeling random.
Two parts of the bill
Every transaction on Solana has the same fee structure. The base fee is fixed, mandatory, and tiny. The priority fee is variable, optional, and tied to how much computation your transaction will use.
The base fee is five thousand lamports per signature. A transaction with one signer pays five thousand lamports total in base fees. A transaction with two signers, say a multisig, pays ten thousand. The amount doesn't change with the size or complexity of what the transaction does. It exists to cover the cost of signature verification, which every validator has to perform, and to put a floor under spam. Half of the base fee gets burned, removed from circulation permanently. The other half goes to the validator that produced the block.
The priority fee is on top of that and is yours to set. It is the way a transaction tells the leader "schedule me ahead of the others." When the network is busy and more transactions arrive than fit in a block, the leader's scheduler sorts the incoming traffic by how much priority fee each transaction is paying per unit of computation, and works through them from highest to lowest. Pay more priority fee, get included sooner. The priority fee goes entirely to the validator, none of it is burned.
Both fees are paid up front, before the transaction runs. If the transaction succeeds, the network keeps the fees and the state changes commit. If the transaction fails, the network still keeps the fees and the state changes roll back. The validator did the work to try, and you pay for the attempt regardless of outcome.
Compute units
The number that gives the priority fee its shape is the compute unit, abbreviated CU. Every operation a Solana program performs costs a fixed number of compute units. Adding two integers, reading a byte from an account, calling another program, hashing some data, each one has a CU cost set by the runtime. The total CU consumption of your transaction is the sum across every operation it executes.
Two CU numbers matter, and they are different things.
The CU limit is the cap your transaction declares for itself. It is the maximum number of compute units the runtime is allowed to spend on you before reverting the transaction with a "compute budget exceeded" error. Each transaction gets a default CU limit if you don't set one explicitly: 200,000 per non-builtin instruction, up to a hard ceiling of 1,400,000 for the entire transaction.
The CU price is how many micro-lamports you are willing to pay per compute unit of that budget. A micro-lamport is one millionth of a lamport, so the formula divides by a million to turn it back into whole lamports: priority_fee = CU_price × CU_limit / 1,000,000.
The catch worth slowing down on is that the priority fee is computed from the CU limit, the cap you reserved, rather than the CU usage, what the program actually spent. If you reserve 200,000 CU and your program only uses 60,000, you still pay priority fee on all 200,000. The leader treats the cap as the resource you locked up, since they had to plan for it being used.
This shapes how production code talks to the network. Set the CU limit too high and every transaction pays priority fee on compute units it never touches, which adds up across thousands of transactions and worse, dilutes your effective bid per CU so the leader treats you as a lower priority than you thought. Set it too low and the transaction reverts mid-execution with a compute budget error, costing you the fee anyway with nothing to show for it. The right move is to simulate your transaction first, see how many CUs it actually consumes, add a margin of ten or twenty percent, and set the limit to that.
The Compute Budget program is what you use to set both values. It is a built-in Solana program with two instructions worth knowing: SetComputeUnitLimit to set the CU cap, and SetComputeUnitPrice to set the per-CU rate. You include them in your transaction alongside your real work, and the runtime reads them before execution to size your budget.
The priority fee market in action
Picture three transactions arriving at the same leader in the same block. Alice's transaction is paying 5,000 micro-lamports per CU. Bob's is paying 100. Carol's is paying zero. All three have the default 200,000 CU limit.
Alice's priority fee comes out to a million lamports. Bob's is twenty thousand. Carol's is zero. The leader's scheduler sorts incoming transactions by priority fee per CU, fills the block from the top of the sorted list, and stops when the block is full. Alice lands first, Bob second if there is room, Carol last or not at all depending on how much demand the leader is seeing.
This is the part the Grape outage of September 2021 forced the network to fix. Before priority fees existed, every transaction was equal in the eyes of the leader. When the network got flooded with low-value bot traffic, important transactions had no way to bid for inclusion ahead of the noise. Adding the priority fee market gave users a tool to express urgency and gave validators a signal for which transactions to favor. It is now the central mechanism the network uses to stay responsive during congestion.
What this means when you write code
When you build a transaction client-side, you add two compute-budget instructions at the start: one to set the CU limit, one to set the CU price. The limit comes from simulating your transaction and adding a safety margin. The price comes from looking at what the network is currently paying for prompt inclusion, which you fetch from your RPC provider or estimate from recent blocks.
When you write a program, you make its CU consumption a number you care about. Cheap programs cost less in priority fees per execution, which matters when users run them millions of times. The cost of a single arithmetic operation is a handful of CU. The cost of a hash is a few thousand. The cost of a cross-program call is in the tens of thousands. Allocating an account is more. These numbers add up, and the difference between a tight program and a loose one shows up in user fees.
When you simulate a transaction before sending it, the simulator returns the actual CU consumption alongside the result. Use that number rather than a guess. Programs change as you develop them, and a margin that was right last month may be wrong this month.