> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana: Understanding the compute budget

> How Solana compute units work — default allocations, SetComputeUnitLimit and SetComputeUnitPrice instructions, and optimizing compute for lower fees.

**TLDR:**

* Every Solana instruction gets a default compute unit (CU) allocation. Non-builtin programs get 200,000 CUs; builtin programs (System, Stake, Vote) get 3,000 CUs.
* The transaction-level cap is 1,400,000 CUs.
* Priority fees are calculated from the **requested** CU limit, not actual usage — overspending on CUs wastes money.
* Use `simulateTransaction` to measure actual CU usage, then set `SetComputeUnitLimit` to the measured value + 10% margin.
* On [transaction v1](/docs/solana-transaction-v1), these settings move out of Compute Budget Program instructions and into a `transactionConfig` field on the message.

## How compute units work

Every transaction on Solana consumes compute units (CUs). CUs are the Solana equivalent of gas — they measure the computational cost of executing instructions. The runtime enforces a CU budget per transaction; if the transaction exceeds it, execution aborts with `ComputationalBudgetExceeded`.

### Default allocation

When you don't include a `SetComputeUnitLimit` instruction, the default budget is calculated based on instruction types:

```
default_cu_limit = (num_builtin_instructions × 3,000)
                 + (num_non_builtin_instructions × 200,000)
```

* **Builtin instructions** (System Program, Stake, Vote, Compute Budget) — 3,000 CUs each per [SIMD-0170](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0170-builtin-instruction-cost-and-budget.md)
* **Non-builtin instructions** (your program, Token Program, any SBF-deployed program) — 200,000 CUs each
* The result is clamped to the transaction cap of **1,400,000 CUs**

A typical transaction with 1 SystemProgram transfer + 1 ComputeBudget instruction + 1 SPL Token instruction gets: `(2 × 3,000) + (1 × 200,000) = 206,000 CUs` as the default budget.

### Why defaults are wasteful

Consider a simple SOL transfer with a priority fee:

* 2 builtin instructions (transfer + SetComputeUnitPrice) = 6,000 CUs allocated
* But the actual transfer uses \~450 CUs

If you set a priority fee of 10,000 micro-lamports per CU, the fee on 6,000 CUs is 60,000,000 micro-lamports (0.06 lamports). If you set `SetComputeUnitLimit` to 500 CUs (enough for the transfer + margin), the fee drops to 5,000,000 micro-lamports — a 12x reduction.

<Warning>
  The priority fee is determined by the **requested** compute unit limit, not the actual number of compute units used. If you set a CU limit that is too high or use the default, you pay for unused compute.
</Warning>

## Compute Budget Program instructions

The Compute Budget Program (`ComputeBudget111111111111111111111111111111`) has 4 instructions:

| Instruction | Parameter | Type | Description |
| - | - | - | - |
| `SetComputeUnitLimit` | `units` | u32 | Max CUs the transaction may consume |
| `SetComputeUnitPrice` | `micro_lamports` | u64 | CU price in micro-lamports (priority fee) |
| `RequestHeapFrame` | `bytes` | u32 | Heap size for each program (32K–256K, multiple of 1024) |
| `SetLoadedAccountsDataSizeLimit` | `bytes` | u32 | Max total bytes of account data the transaction may load |

**Rules:**

* Only **one** of each instruction variant is allowed per transaction. Duplicates cause a `DuplicateInstruction` error and the transaction fails.
* `SetComputeUnitLimit` accepts any u32 but is clamped to 1,400,000.
* `SetComputeUnitPrice` accepts any u64 (0 to u64::MAX).

## Optimizing your compute budget

The optimal workflow is:

1. **Simulate** your transaction to measure actual CU consumption
2. **Add a margin** (10–20%) to the simulated value
3. **Set the CU limit** with `SetComputeUnitLimit`
4. **Set the CU price** with `SetComputeUnitPrice` based on recent priority fees

### Step 1: Simulate and measure

<CodeGroup>
  ```typescript TypeScript theme={"system"}
  import {
    Connection,
    Keypair,
    SystemProgram,
    TransactionMessage,
    VersionedTransaction,
    ComputeBudgetProgram,
  } from "@solana/web3.js";
  import bs58 from "bs58";
  import "dotenv/config";

  const connection = new Connection(process.env.SOLANA_RPC!);
  const payer = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY!));

  async function optimizeComputeBudget() {
    const latestBlockhash = await connection.getLatestBlockhash();

    // Your transaction instructions (without CU limit set yet)
    const instructions = [
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
      SystemProgram.transfer({
        fromPubkey: payer.publicKey,
        toPubkey: payer.publicKey,
        lamports: 1000,
      }),
    ];

    // Build and simulate WITHOUT SetComputeUnitLimit
    const message = new TransactionMessage({
      payerKey: payer.publicKey,
      recentBlockhash: latestBlockhash.blockhash,
      instructions,
    }).compileToV0Message();

    const transaction = new VersionedTransaction(message);
    transaction.sign([payer]);

    const simulation = await connection.simulateTransaction(transaction);
    const unitsConsumed = simulation.value.unitsConsumed || 0;
    console.log("Simulated CUs:", unitsConsumed);

    // Add 10% margin
    const cuLimit = Math.ceil(unitsConsumed * 1.1);
    console.log("Setting CU limit to:", cuLimit);

    // Rebuild with the optimized CU limit
    const optimizedInstructions = [
      ComputeBudgetProgram.setComputeUnitLimit({ units: cuLimit }),
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
      SystemProgram.transfer({
        fromPubkey: payer.publicKey,
        toPubkey: payer.publicKey,
        lamports: 1000,
      }),
    ];

    const optimizedMessage = new TransactionMessage({
      payerKey: payer.publicKey,
      recentBlockhash: latestBlockhash.blockhash,
      instructions: optimizedInstructions,
    }).compileToV0Message();

    const optimizedTx = new VersionedTransaction(optimizedMessage);
    optimizedTx.sign([payer]);

    const sig = await connection.sendTransaction(optimizedTx);
    console.log("Transaction:", sig);
  }

  optimizeComputeBudget();
  ```
</CodeGroup>

## Block-level limits

The Solana scheduler imposes block-level CU caps that affect how many transactions fit per block:

* **48,000,000 CUs per block** — total compute budget across all transactions
* **12,000,000 CUs per account per block** — write-lock limit per account

These block limits are why tight CU budgets matter: a transaction requesting 200,000 CUs that only uses 500 blocks other transactions from fitting in the same block, reducing overall throughput.

## Priority fee calculation

The total priority fee for a transaction:

```
priority_fee = ceil(SetComputeUnitPrice × SetComputeUnitLimit / 1,000,000)
```

Where `SetComputeUnitPrice` is in micro-lamports and the result is in lamports. The division uses ceiling — non-integer results round up. The fee is **always based on the requested limit**, not actual usage.

## Compute budget on transaction v1

Legacy and v0 transactions set the compute budget with [Compute Budget Program instructions](#compute-budget-program-instructions). A [v1 transaction](/docs/solana-transaction-v1) carries the same settings in a `transactionConfig` field on the message instead:

```json theme={"system"}
"transactionConfig": {
  "computeUnitLimit": 117372,
  "heapSize": null,
  "loadedAccountsDataSizeLimit": 14097421,
  "priorityFee": 839349
}
```

Two differences matter when you read v1 traffic:

* The priority fee is a total in lamports, not a rate in micro-lamports per compute unit. A v1 transaction pays `5000 × numRequiredSignatures + priorityFee`, with no further arithmetic.
* Code that derives limits or fees by scanning for Compute Budget instructions finds nothing on a v1 transaction. Read `transactionConfig` when it is present, and fall back to the instruction scan for legacy and v0.

To compare a v0 rate against a v1 total, convert the rate with the [priority fee calculation](#priority-fee-calculation) formula: `ceil(SetComputeUnitPrice × SetComputeUnitLimit / 1,000,000)`.

## Additional resources

* [Priority fees for faster transactions](/docs/solana-how-to-priority-fees-faster-transactions) — practical guide to setting priority fees
* [Estimate priority fees with getRecentPrioritizationFees](/docs/solana-estimate-priority-fees-getrecentprioritizationfees) — dynamic fee estimation
* [Analyzing adjacent transactions for priority fees](/docs/solana-analyzing-adjacent-transactions-for-priority-fees) — advanced fee analysis
* [simulateTransaction](/reference/solana-simulatetransaction) — simulate to measure CU usage
* [Solana: transaction v1 explained](/docs/solana-transaction-v1) — the `transactionConfig` field and the fee unit change
