Solana Durable Nonce: When You Actually Need One

How durable nonces remove blockhash expiry, what an advanceNonce instruction costs you, and the specific cases where they help rather than add complexity.

BoltTx Team··9 min read
solanadurable-nonceblockhashtransaction-landingmultisigrpc

Every normal Solana transaction carries a recent blockhash that expires after roughly 150 blocks — about 60 seconds. Miss that window and the transaction is permanently invalid.

A durable nonce replaces that blockhash with a value stored in an account you control, which does not expire on a timer. Useful in a small number of situations, and unnecessary overhead in most.

What a Nonce Account Actually Is

An on-chain account holding a nonce value plus an authority. The value only changes when someone runs an advanceNonce instruction against it.

That is the whole mechanism, and it has one consequence that matters: ★a transaction signed against a nonce stays valid until the nonce advances, however long that takes.★

The cost is that every such transaction must begin with nonceAdvance as its first instruction. That instruction both consumes the current nonce and generates the next one, which is what prevents replay.

import {
  Connection, Keypair, SystemProgram, Transaction, NONCE_ACCOUNT_LENGTH,
} from "@solana/web3.js";

// One-time setup: create and initialise the nonce account.
const nonceAccount = Keypair.generate();
const rent = await connection.getMinimumBalanceForRentExemption(
  NONCE_ACCOUNT_LENGTH,
);

const tx = new Transaction().add(
  SystemProgram.createAccount({
    fromPubkey: payer.publicKey,
    newAccountPubkey: nonceAccount.publicKey,
    lamports: rent,
    space: NONCE_ACCOUNT_LENGTH,
    programId: SystemProgram.programId,
  }),
  SystemProgram.nonceInitialize({
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: nonceAuthority.publicKey,
  }),
);

★The account is rent-exempt, so the lamports are locked but not spent.★ You get them back if you close the account with nonceWithdraw.

Using One

Three differences from a normal transaction:

// 1. Read the current nonce value from the account.
const info = await connection.getNonce(nonceAccount.publicKey);

const tx = new Transaction();

// 2. advanceNonce must be the FIRST instruction.
tx.add(
  SystemProgram.nonceAdvance({
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: nonceAuthority.publicKey,
  }),
);

tx.add(yourActualInstruction);

// 3. recentBlockhash is set to the nonce value, not a real blockhash.
tx.recentBlockhash = info.nonce;
tx.feePayer = payer.publicKey;

★If nonceAdvance is not first, the transaction fails.★ This is the most common implementation mistake, and the error is not obvious from the failure message.

If your problem is transactions expiring under congestion rather than needing long-lived validity, a free BoltTx key is a simpler fix to test first.

When a Durable Nonce Actually Helps

Multisig approvals. A transaction that needs several signatures collected over hours or days cannot use a recent blockhash. This is the canonical use case, and durable nonces exist largely for it.

Hardware wallet flows with human delay. Signing that waits on a person, a device confirmation, or an approval queue can easily exceed the blockhash window.

Pre-signed transactions. Anything built now and submitted on a trigger later — a conditional order, a scheduled operation, a contingency transaction sitting ready.

Offline signing. An air-gapped signer producing a transaction that gets carried to a connected machine.

When It Does Not Help

★This is the part worth being blunt about, because durable nonces get recommended for problems they do not solve.★

Transactions failing during congestion. A nonce removes expiry. It does nothing about priority fee, submission routing, or validator acceptance. If your transactions are not landing because block space is contested, the nonce keeps a doomed transaction valid for longer rather than helping it land.

Trading bots that need speed. You now have an extra account read, an extra instruction, and a serialised dependency on nonce state. For a bot with a sub-second decision cycle, ★a background-refreshed recent blockhash is both simpler and faster.★

Retry loops. Continuous resubmission until the blockhash expires already handles the ordinary retry case. A nonce lets you retry for longer, which is rarely the constraint — if a minute of retrying did not land it, another ten will not.

The Serialisation Problem

Here is the limitation that surprises people building high-volume systems.

★A nonce account can only support one in-flight transaction at a time.★ The nonce advances when a transaction using it lands, which invalidates every other transaction signed against the same value.

tx A and tx B both signed against nonce value N
  → A lands, nonce advances to N+1
  → ★B is now permanently invalid★

So concurrency requires a pool of nonce accounts, one per in-flight transaction, each rent-exempt. For a bot sending many transactions per second that is a meaningful amount of locked capital and bookkeeping — which is another reason durable nonces and high-frequency trading are a poor match.

Failure Modes

nonceAdvance not first. The transaction is rejected. Always the first instruction, no exceptions.

Stale nonce value. You read the nonce, something else advanced it, your transaction is invalid. Re-read before signing if anything else can touch the account.

Wrong authority. The authorizedPubkey must sign. A common error when the nonce authority differs from the fee payer, which is normal in multisig setups.

Account not rent-exempt. Underfunding at creation means the account can be garbage collected. Always use getMinimumBalanceForRentExemption rather than a hardcoded figure.

Forgetting the account still exists. Rent-exempt lamports stay locked until you nonceWithdraw. Abandoned nonce accounts are quietly locked capital.

What Landing Looks Like

Real transactions through our delivery nodes: median confirmation 336ms — under one slot.

★Most transactions land far inside the blockhash window.★ If yours are expiring, the cause is usually not the window being too short — it is fee, routing, or a retry loop that stopped early.

Deciding

A short test:

Does the transaction need to stay valid for more than a minute?
  ├─ Yes, because a human or multiple parties must sign  → ★durable nonce★
  ├─ Yes, because it is pre-signed for a later trigger   → ★durable nonce★
  └─ No, it just keeps failing under congestion          → ★fee, retry, routing★

The third branch is where most people arrive, and a nonce is the wrong tool for it.

Where BoltTx Fits

We handle submission, which is the third branch above.

Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure, so a transaction is not observable in transit before it lands. Durable-nonce transactions submit the same way as any other — the nonce affects validity, not routing.

You sign locally. We never hold funds, never sign, and never modify transaction contents. The tip travels inside the transaction, paid on chain from your own wallet, and reverts with the transaction if it fails, because that is how Solana handles atomic transactions. You pay only on transactions that reach the chain.

Get a free API key. No monthly fee:

const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

FAQ

What is a durable nonce on Solana? An on-chain account holding a nonce value that replaces the recent blockhash in a transaction. Because the value only changes when an advanceNonce instruction runs, the transaction does not expire on a timer.

When should I use a durable nonce? When a transaction must stay valid longer than the roughly 150-block blockhash window: multisig approvals collected over time, hardware wallet flows with human delay, pre-signed conditional transactions, and offline signing.

Does a durable nonce help transactions land during congestion? No. It removes expiry, not contention. Landing depends on priority fee, retry behaviour, and submission routing. A nonce keeps a transaction valid longer without making it more likely to be included.

How do I create a Solana nonce account? Create an account of NONCE_ACCOUNT_LENGTH funded to rent exemption, then run SystemProgram.nonceInitialize with the authority that will sign advances. Use getMinimumBalanceForRentExemption rather than a hardcoded amount.

Why does my durable nonce transaction fail? Most often because nonceAdvance is not the first instruction, which is a hard requirement. Other causes are a stale nonce value, the wrong authority signing, or an account that was never rent-exempt.

Can I use one nonce account for multiple transactions at once? No. When a transaction using the nonce lands, the nonce advances and every other transaction signed against the old value becomes invalid. Concurrency requires a pool of nonce accounts.

How much does a nonce account cost? The rent-exemption balance for NONCE_ACCOUNT_LENGTH, which is locked rather than spent. You recover it by closing the account with nonceWithdraw.

Should a trading bot use durable nonces? Usually not. You add an account read, an extra instruction, and a serialised dependency, in exchange for removing an expiry that a fast bot never hits. A background-refreshed recent blockhash is simpler and faster.

How long does a durable nonce transaction stay valid? Until the nonce advances. There is no time limit — a transaction signed against a nonce can be submitted days later, as long as nothing else advanced that nonce in the meantime.

What is the difference between a nonce and a recent blockhash? A recent blockhash comes from the chain and expires after about 150 blocks. A nonce comes from an account you control and changes only when you advance it. Both occupy the same field in the transaction.

Do I need to re-read the nonce before every transaction? If anything else can advance that account, yes. If a single process owns the nonce and tracks its own advances, you can maintain the value locally and re-read only on failure.

Can I close a nonce account and get the lamports back? Yes, with SystemProgram.nonceWithdraw signed by the nonce authority. Abandoned nonce accounts hold locked lamports indefinitely otherwise.

Does using a durable nonce cost extra fees? The advanceNonce instruction adds compute units, which adds a small amount to your fee, plus rent-exemption lamports locked in the account. Neither is large, but both are real.

Are durable nonces useful for multisig? This is the primary use case. Collecting signatures from several parties takes longer than a blockhash lives, and a nonce makes that possible without repeatedly rebuilding the transaction.

Why do my transactions expire even though they seem fast? Log the gap between fetching the blockhash and submitting. A fetch at startup, a signing step that waits on something, or a retry loop that keeps resending expired bytes will all produce this without the network being slow.

Back to all posts