Pricing the Load — Local Fee Markets & Priority Fees
The previous page fixed the ingress: it gave the leader a way to tell real senders from a flood, so a spammer can no longer drown the front door for free. That is a transport-layer fix — it decides who gets to speak. But it does not, by itself, decide what speaking should cost. A well-connected, well-staked sender can still flood; QUIC and stake-weighted QoS only make the flood come from someone the network can see and rate-limit, not from an anonymous firehose.
This page adds the missing half: an economic backpressure. It closes the loop opened three pages back in No Fee Market, and How Spam Amplifies, where we found the real root cause of the early outages — a chain so cheap that flooding it was free, and so parallel that the flood got amplified around a few hot accounts. The fix has two parts that fit together exactly: priority fees put a price on jumping the queue, and local fee markets make that price rise only for the accounts that are actually hot, so one frenzy can’t tax the whole chain. By the end you’ll see why this is not a bolt-on tax but the direct economic shadow of Sealevel’s account model — the same declaration that enables parallel execution is what lets Solana price congestion locally.
The root cause, restated in one line
Section titled “The root cause, restated in one line”Everything on this page follows from a single sentence you can carry from the spam-amplification page:
When inclusion is nearly free and ordering is decided without a price, the only way to win a contested slot is to send more — so demand for a scarce resource is expressed as volume, and volume is exactly what melts a validator’s ingress and scheduling stages.
The failure is economic before it is technical. A flat, near-zero fee means the marginal cost of one more transaction is ~0, so a rational actor who really wants in sends thousands and retries. That is not abuse of a bug; it is the correct strategy given the incentives. The engineering fix, then, is to change the incentives: make “how badly do you want in?” a question you answer with price, not with packet count.
no priced ordering: want in more → send more txs → retry-spam → ingress melts priced ordering: want in more → bid more per CU → pay for it → spam stops payingPriority fees: a bid for inclusion, priced per compute unit
Section titled “Priority fees: a bid for inclusion, priced per compute unit”Solana already charges a base fee — a fixed 5,000 lamports per signature — for the privilege of being included at all (the full mechanics live on the economics fees page). The base fee is permission. It says nothing about when you land, and in a quiet slot it doesn’t need to. The problem only appears when more transactions want a slot — or want to write the same account — than can fit.
A priority fee (also called a prioritization fee) is the answer. It is an optional, per-compute-unit bid layered on top of the base fee, attached through a Compute Budget instruction. You declare two things: how many compute units your transaction may consume, and how many micro-lamports (millionths of a lamport) you will pay for each one. The total priority fee is their product, and the leader can order pending transactions by what they are willing to pay for the slot capacity they consume.
priority_fee = (compute units requested) × (price per CU, in micro-lamports)
base fee : fixed toll to enter (5,000 lamports / signature) — buys INCLUSION priority fee : optional bid for ordering (micro-lamports per CU) — buys GOING FIRSTWhy does this restore backpressure where a flat fee could not? Because it puts a floor under the cost of urgency. Under a flat fee, the way to express “I want in more than the next person” was to send more copies and hope one lands first — free to attempt, so everyone does it, so the ingress drowns. Under a priority fee, “I want in more” costs strictly more lamports per attempt. Spam is no longer a free lever; it is a paid one, and the moment a scarce slot is worth bidding for, brute-force volume stops being the cheapest way to win it.
// A priority fee is set with two Compute Budget instructions, prepended to your// transaction. This is the real Solana SDK shape (solana-sdk / compute_budget).use solana_sdk::compute_budget::ComputeBudgetInstruction;
let instructions = vec![ // 1. Cap how many compute units this transaction may use. ComputeBudgetInstruction::set_compute_unit_limit(200_000), // 2. Bid a price per CU, in micro-lamports. THIS is the priority fee. ComputeBudgetInstruction::set_compute_unit_price(1_000), // ...then your actual program instruction(s) follow.];// priority fee paid = 200_000 CU × 1_000 µL/CU = 200_000_000 µL = 200 lamports// total fee = 5_000 (base) + 200 (priority) = 5_200 lamportsNote what the bid is denominated in: compute units, the runtime’s unit of scarce block capacity. Bidding per CU means a transaction that reserves more of the slot pays proportionally more to jump the queue — the auction is priced in the exact resource that is scarce, not in a flat tip that ignores how much of the block you’re taking.
Local fee markets: the war stays where the heat is
Section titled “Local fee markets: the war stays where the heat is”A priority fee alone would be a real improvement, but it would recreate a subtler version of the original problem if the auction were global — one chain-wide price for ordering. Then a frenzy on a single hot account would drive the priority price up for everyone in the block, and a transaction that never touched the hot account would still have to outbid the mob to land. That is precisely Ethereum’s EIP-1559 shape: one global base fee per block, so one hot contract taxes the whole network. It would leave the amplification half of our root cause untouched.
Solana avoids this because it knows something Ethereum structurally cannot: which accounts each transaction will touch, before it runs. Every Solana transaction declares its footprint, and the conflict rule says two transactions collide only when they share a writable account. So the runtime knows exactly which account each transaction is contending for — and it can scope the priority-fee auction to that account. That scoped auction is a local fee market: the price of priority rises only for transactions writing a hot account; everyone else in the same slot is untouched.
┌──────────────────────── one slot ────────────────────────┐ │ │ │ writes hot_mint ← FRENZY: thousands contend │ │ tx tx tx tx tx ... ← priority fee here SPIKES │ │ │ │ writes SOL/USDC pool ← cool: a handful of txs │ │ tx tx ← priority fee here stays ~0 │ │ │ │ writes your wallet ← cool: just you │ │ tx ← base fee only, no bidding │ └────────────────────────────────────────────────────────────┘
→ the frenzy prices ONLY the hot account. The swap and the wallet transfer pay their normal, near-zero fee in the same block.The mint’s fee market and the swap’s fee market are different markets in the same block. Bidders for the hot account fight each other for its limited serial throughput — the hot-account ceiling proved those writes must serialize, so there is a real, scarce resource to auction — but that fight is invisible to a transaction touching different accounts. The chain does not have one congestion price. It has one price per contended account.
Why localization is the part that matters for reliability
Section titled “Why localization is the part that matters for reliability”Restoring backpressure (priority fees) counters spam; localizing it (local fee markets) is what protects the reliability of the chain during a frenzy. Trace it against the outage story:
- A memecoin launch or an NFT mint concentrates writes on one account. Under the old flat-fee scheme, that demand had exactly one release valve — retry-spam — and the spam globalized: it congested ingress and scheduling for transactions that never touched the hot account. That is the amplification that turned a local frenzy into a network-wide brownout.
- With local fee markets, the frenzy’s demand is expressed as a bidding war confined to the hot account. Writers of that account pay more; disjoint traffic keeps clearing at the base fee. The frenzy is priced where it happens instead of spilling everywhere it doesn’t.
Global pricing (naive): one hot account congested → EVERYONE in the block pays more, and retry-spam globalizes the congestion (the 2021–2024 shape)
Local fee markets: one hot account congested → only writers of THAT account bid up; disjoint traffic keeps flowing at base fee, ingress stays clearRead that against the schedule and the reliability chapter closes on itself. The scheduler already partitioned the world by writable account — that is what a conflict-free batch is. Local fee markets price the world along the exact same seam: the unit of contention (one hot account’s serial lane) is the unit of pricing (that account’s fee market). The fee market didn’t invent a new abstraction; it put a price on the scarce resource Sealevel had already isolated. Because contention is per-account, the fee market is per-account — and because it is per-account, one frenzy can no longer take the whole chain down with it.
Under the hood — why this directly counters amplification
Section titled “Under the hood — why this directly counters amplification”The spam-amplification page named the mechanism: a flood aimed at a hot account can’t parallelize, so the scheduler serializes it, so the backlog builds and spills into ingress. Local fee markets attack that mechanism at its economic root. Sustained flooding of a hot account now has a rising marginal cost: as more writers pile onto the account, its local priority price climbs, so each additional attempt costs more than the last. The flood is no longer free to sustain — it gets more expensive precisely as it gets more dangerous.
attacker's cost to keep flooding ONE hot account:
flat fee, no local market: cost per attempt ≈ constant, near-zero → sustain the flood indefinitely for pennies
local fee market: cost per attempt rises with the account's contention → sustaining the flood costs strictly, and increasingly, moreThis is the point where the reliability fix and the economics fix are the same fix. Making the hot account expensive is what turns “flood it and retry” from a winning strategy into a losing one — and it does so without raising the price of the cold accounts that make up the rest of the block. Contrast this with the brute-force alternative: you could fight spam by raising the base fee for everyone, but that taxes the honest wallet transfer as much as the attacker’s flood. The local fee market taxes only the lane under attack, which is why it is a reliability tool and not just a revenue one.
What this does not fix
Section titled “What this does not fix”Be precise about the boundary of the fix, because it is easy to over-claim. Local fee markets price
contention; they do not remove it. A hot account is still a single serial lane — the
hot-account ceiling is physics, not policy. Priority fees turn the
scramble for that lane into an orderly auction, which stops the network-wide spillover, but they don’t make
the lane wider. If your application funnels the world through one writable account, you will pay an
ever-rising local fee to keep contending on it. The runtime-side answer to that is not more fees; it is
sharding the hot account into K disjoint accounts so the scheduler finds K parallel lanes (covered on
the hot-account ceiling page). Fees ration the scarcity honestly;
data layout is how you reduce it. The two are complementary, and a healthy Solana program uses both.
The architect’s lens
Section titled “The architect’s lens”Priority fees and local fee markets are the economic layer that sits directly on top of the reliability story, so they earn the five questions.
- Why does it exist? Because a near-zero, unpriced fee let users express urgency as volume — flood and retry — and volume is exactly what melts a validator’s ingress. Priority fees make urgency cost lamports instead of packets, restoring the economic backpressure that a flat fee threw away.
- What problem does it solve? It localizes congestion. Bidding for a hot account’s scarce serial lane stays scoped to that account (a local fee market), so unrelated disjoint traffic keeps clearing at the base fee instead of being priced out — or spammed off the network — by someone else’s mint or token launch.
- What are the trade-offs? It raises cost and complexity: wallets must now estimate a per-CU bid rather than pay one visible flat price, misjudging it means overpaying or getting dropped, and a hot account’s fee can spike. The mechanism prices the scarcity; it does not remove it — the account is still serial.
- When should I avoid it? You don’t avoid the base fee, and you skip the priority fee when the slot isn’t contested — bidding for ordering in a quiet moment is wasted lamports. And rather than lean on an ever-rising local fee for a central hot account, you shard it so the contention drops instead of the bill rising.
- What breaks if I remove it? Remove priority fees and urgency reverts to retry-spam, drowning ingress again. Remove local markets and you’re back to a global price: one hot account taxes the whole block, and the amplification that caused the 2021–2024 storms returns — a local frenzy once more becomes a network-wide brownout.
Check your understanding
Section titled “Check your understanding”- A priority fee is “an optional per-compute-unit bid on top of the base fee.” Explain what each part of that phrase means, and why pricing urgency this way restores backpressure that a flat, near-zero fee could not.
- Solana can price congestion per account where Ethereum prices it per block. What single design fact makes that possible, and how does the runtime use it to scope the priority-fee auction to one hot account?
- During a memecoin frenzy, thousands of transactions hammer one hot market account while an unrelated wallet transfer sits in the same slot. Walk through why the frenzy raises fees only for writers of the hot account and leaves the transfer paying the base fee.
- This page claims local fee markets “directly counter spam amplification.” Explain the mechanism: what happens to the cost of sustaining a flood against one hot account, and why that is a reliability fix and not merely a revenue one.
- What does this fix not solve, and what is the correct tool for the part it leaves on the table?
Show answers
- Optional — you can skip it in an uncontested slot and still land on the base fee alone. Per compute unit — it’s a price in micro-lamports per CU, so you pay in proportion to the scarce block capacity you reserve, not as a flat tip. A bid on top of the base fee — the base fee buys inclusion (permission), the priority fee buys ordering (going first). It restores backpressure because a flat near-zero fee made “send more and retry” free, so everyone flooded and ingress melted; a per-CU bid makes urgency cost strictly more lamports per attempt, so brute-force volume stops being the cheapest way to win a contested slot.
- Every Solana transaction declares the accounts it will touch up front, and two transactions conflict only when they share a writable account. So the runtime knows exactly which account each transaction is contending for before it executes, and can scope the priority-fee auction to that account — a local fee market. Ethereum’s contracts hold their own state, so the runtime can’t know what a call touches until it runs it, leaving one queue, one ordering, one global price.
- Every transaction declares its writable accounts, so the runtime sees that the frenzy’s transactions all contend for the hot market account while the transfer writes only its own wallet. The scheduler serializes only the hot-account writers, making that account’s serial throughput the scarce resource, so the priority-fee auction is scoped to it. The transfer touches a disjoint account, isn’t in that market, and pays only the base fee.
- Under a flat fee, sustaining a flood against a hot account costs ~0 per attempt, so it can run indefinitely for pennies. With a local fee market, the account’s local priority price rises with its contention, so each additional flooding attempt costs more than the last — the flood gets more expensive precisely as it gets more dangerous, which makes “flood and retry” a losing strategy. It’s a reliability fix (not just revenue) because it taxes only the lane under attack — the cold accounts in the rest of the block stay cheap — whereas raising the base fee for everyone would tax the honest transfer as hard as the flood.
- It prices contention but doesn’t remove it: a hot account is still a single serial lane (the
hot-account ceiling is physics). Priority fees stop the network-wide spillover but don’t widen the lane, so
funnelling everything through one account means paying an ever-rising local fee. The correct tool for that
part is sharding the hot account into
Kdisjoint accounts so the scheduler findsKparallel lanes — data layout reduces the contention that fees can only ration.