SOLSTACKAcademy

Advanced· Lesson 3 of 8· 3 min

Versioned transactions and lookup tables

A transaction must fit in one 1,232-byte packet, and every account it touches costs 32 of those bytes. Lookup tables cut that to one byte each, and version 0 is the message format that can use them.

A legacy message lists every account in full. Header and blockhash take about 70 bytes, each signature 64, and each account key 32; after the instruction data there is room for roughly 35 accounts. A multi-hop swap, a batched airdrop or a launchpad settlement can touch more than that, and simply does not fit.

Version 0

A v0 message starts with a version byte, then the same header, static account keys, blockhash and instructions as before, and adds a list of address table lookups: for each table, its address plus the indexes of the entries to load as writable and as read-only. Before executing, the runtime reads the tables and appends the resolved addresses to the account list — static keys first, then the writable lookups, then the read-only ones. Instructions index into that combined list.

Solana Explorer's summary for a v0 swap: fee payer, blockhash, fee, cost, compute, version V0 and a size of 766 of 1,232 bytes
  1. Version V0: the message carries table lookups.
  2. 766 bytes on the wire for a transaction touching 32 accounts. As a legacy message it would not have fit.
  3. The fee payer, and every other signer, must be a static key. Lookups cannot sign.
  4. Compute is unaffected by the format; the tables only change the encoding.
A versioned transaction on Solana Explorer, captured 19 Sep 2026 · explorer.solana.com
Solscan's fee panel listing the three lookup table accounts the swap used
  1. Version 0.
  2. The first of three tables. Jupiter maintains tables of pool and program addresses for its routes.
  3. Twenty-one of the transaction's accounts came from these three tables.
The same transaction's tables on Solscan, captured 19 Sep 2026 · solscan.io

Inside a table

An address lookup table is an account owned by the Address Lookup Table program, AddressLookupTab1e1111111111111111111111111, holding up to 256 addresses. An authority creates it, extends it in chunks, and can deactivate it; a deactivated table can be closed and its rent reclaimed after a cool-down of a few hundred slots, so a transaction in flight never loses its table. Entries are append-only: an index always means the same address, which is what makes referencing by index safe.

Solana Explorer's page for an address lookup table: activation status, last extended slot, authority, and the first entries
  1. Explorer recognised the account's owner and decoded it as a lookup table.
  2. Active. A deactivated table shows the slot it stops being usable.
  3. When it was last extended. Tables grow in chunks of up to ~30 addresses per transaction.
  4. The authority that can extend or deactivate it. Anyone can read from it.
  5. Index 0. A v0 message references this address with the single byte 0.
  6. Entries can be anything: wallets, pools, programs. This one is a Jito sentinel address.
One of the swap's three tables, captured 19 Sep 2026 · explorer.solana.com

Rules and edges

  • Signers, including the fee payer, must be static keys. Tables supply non-signing accounts only.
  • A table must be active and, for safety, extended at least one slot before the transaction that uses it.
  • Explorers and RPC nodes resolve the tables to show you full addresses. The wallet sees the resolved accounts in simulation too.
  • Old clients choke on v0. The RPC error is explicit about the fix.
Code
// getTransaction without the flag, on a v0 transaction:
Transaction version (0) is not supported by the requesting client.
Please try the request again with the following configuration parameter:
  "maxSupportedTransactionVersion": 0

When you need one

Any time a transaction fails to build because it is too large: routes across several pools, batches of transfers where every recipient is a new account, instructions that take a long list of remaining accounts. Creating a table is three transactions — create, extend, wait a slot — and the table can be reused by every transaction after. Every current wallet signs v0, and every Solstack tool builds v0 when a transaction would otherwise not fit.

JavaScript
const [ix, tableAddress] = AddressLookupTableProgram.createLookupTable({
  authority: payer.publicKey, payer: payer.publicKey, recentSlot: slot,
});
const extend = AddressLookupTableProgram.extendLookupTable({
  lookupTable: tableAddress, authority: payer.publicKey, payer: payer.publicKey,
  addresses: [...accountsToStore],
});
// later: new TransactionMessage({ ... }).compileToV0Message([tableAccount])

What to remember

  • The 1,232-byte cap fits ~35 full account keys. Lookup tables replace 32-byte keys with 1-byte indexes.
  • A v0 message adds table lookups; the runtime resolves them before execution, static keys first.
  • Tables are append-only accounts of up to 256 addresses, owned by an authority, reusable by anyone.
  • Signers must be static. Tables supply non-signing accounts only.
  • Ask for maxSupportedTransactionVersion: 0 when reading, or the RPC refuses v0 transactions.

Try it