Guide
Solana durable nonce accounts explained
Most Solana transactions die within about a minute. They carry a recent blockhash that expires after roughly 150 slots, which is why offline signing, slow multisig approvals, and "sign now, send later" workflows fail with blockhash not found. Durable nonce accounts solve that narrow problem: instead of anchoring a transaction to a fleeting slot hash, you anchor it to an on-chain nonce value that only advances when you explicitly consume it. This guide explains when durable nonces are worth the complexity, how the account model works, the exact instruction ordering validators require, and the security mistakes that turn a nonce account into a replay hazard.
Recent blockhash vs durable nonce
A normal Solana transaction references the hash of a recent block. Validators accept it only while that hash is still inside the sliding replay-protection window — typically under 90 seconds of wall-clock time on a healthy network. Our blockhash and transaction expiry guide covers that lifecycle in depth.
A durable nonce transaction replaces the recent blockhash field with
the current value stored in a dedicated nonce account. The first
instruction in the transaction must be SystemProgram::AdvanceNonceAccount,
which atomically bumps the stored nonce and authorizes the rest of the instructions to
execute. Because the nonce value does not expire with slot height, you can sign the
transaction offline on an air-gapped machine, pass it through a 3-of-5 multisig over
several days, or queue it in a cron job — as long as nobody else advances that nonce
first.
The trade-off is operational overhead: you must create and fund a rent-exempt nonce account, designate a nonce authority pubkey, and follow strict construction rules. For a wallet swap or game bet that should land in seconds, a fresh blockhash is simpler and safer.
What lives inside a nonce account
A nonce account is a normal Solana account owned by the System Program. Its data layout (after initialization) stores:
- Version — currently 0 for standard nonce accounts.
- State —
Initializedonce set up; uninitialized accounts cannot be used. - Authorized pubkey — the nonce authority allowed to advance the nonce or withdraw lamports.
- Nonce hash — a 32-byte value that acts as the transaction's blockhash substitute.
- Fee calculator — legacy field; modern clients read fees from the cluster directly.
The account must hold enough lamports to be rent-exempt (on the order of
0.00144 SOL at typical rent parameters — check live rent exemption for the exact nonce
account size). The nonce authority is often the same keypair as the fee
payer, but they can differ: a treasury multisig might be authority while a hot wallet pays
fees. Only the authority can sign AdvanceNonceAccount or withdraw leftover
rent if you close the account.
Nonce accounts are plain data accounts, not PDAs. You generate a fresh keypair for the account address unless your tooling abstracts that away. See the Solana account model guide for how ownership, rent, and data size interact across account types.
Creating and initializing a nonce account
Setup is a two-step on-chain flow (often batched into one transaction):
- Create account — allocate space for the nonce state and fund it to rent-exemption. The System Program creates the account at a new pubkey.
- Initialize nonce — call
SystemProgram::InitializeNonceAccountwith your chosen nonce authority pubkey. The cluster seeds the initial nonce hash from a recent blockhash at initialization time.
In @solana/web3.js, helpers like
SystemProgram.createNonceAccount wrap both instructions. The payer funds
creation; the nonce authority does not need to sign initialization unless it is also the
payer. After confirmation, fetch the account with getAccountInfo or
NonceAccount.fromAccountData to read the current nonce hash — that value
becomes the recentBlockhash field when you build the durable transaction
(despite the field name, it holds the durable nonce, not a recent blockhash).
Rotating or closing
To reclaim rent, the nonce authority can withdraw all lamports once no in-flight transactions reference the account. Production systems sometimes maintain a pool of nonce accounts so parallel outbound payments do not contend on a single advancing nonce — each account serializes only its own queue.
Building a durable nonce transaction
Instruction order is not cosmetic — validators reject malformed nonce transactions.
- First instruction:
AdvanceNonceAccounttargeting your nonce account, signed by the nonce authority. - Remaining instructions: your actual logic — transfers, program calls, memo, etc.
- Blockhash field: set to the nonce hash read from the account at build time (not
getLatestBlockhash). - Fee payer: any funded signer; does not have to be the nonce authority.
When the transaction lands, the runtime executes AdvanceNonceAccount first.
That instruction checks that the transaction's blockhash field matches the stored nonce,
then writes a new nonce derived from the previous blockhash chain. If the
transaction fails after advancement, the nonce still moved — you cannot retry the same
signed bytes. Treat durable transactions like single-use tickets.
Always simulate before asking signers to approve. Simulation catches program errors without consuming the nonce. Our transaction simulation guide walks through preflight flags and common false positives.
Offline and multisig signing
Because the nonce hash stays valid until advanced, a hardware wallet can sign on an offline machine. A multisig can collect signatures over days: each cosigner adds their signature to the same serialized transaction; the broadcaster submits once the threshold is met. The bottleneck becomes coordination, not slot time. If another party advances the nonce while you collect signatures, your partially signed transaction is dead — monitor the account or serialize access with a queue.
When to use durable nonces (and when not to)
Good fits
- Offline / air-gapped signing — cold keys that cannot call RPC for a fresh blockhash.
- Slow multisig treasuries — DAO or custody workflows where humans approve over hours.
- Scheduled or batched disbursements — payroll crons that build transactions ahead of send time.
- Relayers with signing delay — backend constructs a tx, user approves asynchronously, relayer submits later.
Poor fits
- Consumer wallet flows — swaps, NFT mints, and game bets should fetch a recent blockhash and send immediately.
- High-frequency trading — nonce serialization adds latency; recent blockhashes are faster.
- When you only need a few extra seconds — refresh blockhash and re-sign instead of operating nonce infrastructure.
If your failure mode is occasional RPC lag, fix RPC fallbacks and priority fees before introducing nonce accounts. See priority fees explained for landing transactions inside the normal blockhash window during congestion.
Security and operational pitfalls
- Nonce draining / front-running — anyone who possesses a fully signed durable transaction can submit it. Protect serialized txs like private keys. Use HTTPS, encrypted storage, and least-privilege relayers.
- Double advancement — two operators submitting different txs against the same nonce account: one wins, the other fails with a nonce mismatch. Use per-purpose nonce accounts or an outbound queue.
- Stale partial multisigs — cosigners who signed against nonce value N while the chain advanced to N+1 waste effort. Display the nonce hash in your signing UI.
- Authority compromise — the nonce authority can advance or drain the account. Prefer multisig authorities for treasury nonces and rotate keys on departure.
- Assuming immutability after failure — a failed durable tx still consumes the nonce. Rebuild with the new hash before re-signing.
- Confusing devnet and mainnet — nonce accounts are cluster-specific. A mainnet-signed tx never lands on devnet.
Durable nonces remove time expiry but not replay protection: each nonce value works once. That is the same guarantee recent blockhashes provide, just with a longer shelf life.
Debugging common errors
- Blockhash not found on a nonce tx — the blockhash field does not match the account's current nonce hash; re-fetch the account and rebuild.
- Invalid account data for instruction — nonce account not initialized, wrong owner, or authority mismatch on
AdvanceNonceAccount. - Instruction index 0 must be advance nonce — reorder instructions; nothing may precede
AdvanceNonceAccount. - Signature verification failed — nonce authority did not sign the advance instruction, or fee payer lacks funds.
- Transaction already processed — you resubmitted identical signed bytes after a successful landing; advance the nonce and create a new tx for new intent.
Log the nonce account pubkey, stored hash, and authority on every build. When production incidents strike, those three fields explain most rejections without guessing.
Key takeaways
- Durable nonce accounts replace recent blockhashes for transactions that must stay valid across long signing or approval delays.
- The first instruction must be
AdvanceNonceAccount, signed by the nonce authority; the transaction's blockhash field holds the current nonce hash. - Each successful landing advances the nonce — failed attempts after advancement still burn the nonce value.
- Use nonce pools and queues when multiple outbound transactions cannot share one account.
- Most dApps should keep using fresh blockhashes; reach for durable nonces only when business logic genuinely cannot sign and send within a minute.
Related reading
- Solana blockhash and transaction expiry — the default short-lived model durable nonces replace
- Solana transaction simulation — preflight before consuming a nonce
- Solana account model — rent, ownership, and account data layout
- Versioned transactions and lookup tables — composing large instruction bundles alongside nonce flows