Address Lookup Tables in Practice
Use Address Lookup Tables (ALTs) with versioned (v0) transactions to fit more accounts in one transaction without exceeding packet size limits.
Recipe
Quick-reference recipe card - copy-paste ready.
solana address-lookup-table create
solana address-lookup-table extend <ALT_ADDRESS> <PUBKEY1> <PUBKEY2>
solana address-lookup-table freeze <ALT_ADDRESS>When to reach for this:
- Jupiter-style routes referencing dozens of accounts.
- Bundling multiple instructions with overlapping account sets.
- Shrinking serialized transaction size for relayers.
- Migrating from legacy txs that hit size errors.
Working Example
solana config set --url devnet
solana airdrop 2
# Create lookup table (returns table address)
solana address-lookup-table create
ALT="<LOOKUP_TABLE_ADDRESS>"
solana address-lookup-table extend "$ALT" \
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \
YOUR_PROGRAM_ID
# Wait for slot activation (~1 slot) then use in v0 tx from client
solana address-lookup-table get "$ALT"import { createSolanaRpc, address } from "@solana/kit";
const rpc = createSolanaRpc(process.env.RPC_URL!);
const alt = await rpc
.getAddressLookupTable(address("ALT_PUBKEY"))
.send();
console.log("addresses:", alt.value?.data.addresses.length);What this demonstrates:
- ALT stores static pubkey list on-chain once.
- v0 transactions reference accounts by index into ALT plus static keys.
- Extension requires authority signature until frozen.
Deep Dive
How It Works
- Lookup table account holds vector of pubkeys.
- Versioned message compresses 32-byte keys to 1-byte indices for ALT entries.
AddressLookupTableProgrammanages create/extend/deactivate/close.- Clients compile v0 messages with
addressTableLookupsfield populated.
ALT Lifecycle
| Step | Action |
|---|---|
| Create | Allocate table account |
| Extend | Append pubkeys (authority) |
| Activate | Wait ~1 slot before use |
| Freeze | Optional immutability |
| Deactivate | Cooldown before close |
TypeScript Notes
// @solana/kit 7.0.0 supports versioned transaction building
// Fetch ALT accounts with getAddressLookupTable before compileGotchas
- Using ALT before activation slot - transaction fails to compile or verify. Fix: wait one slot after extend.
- Legacy transaction with many accounts - exceeds 1232-byte packet limit. Fix: migrate to v0 + ALT.
- Stale ALT entries - closed accounts still in table. Fix: extend new table version; deactivate old.
- Wrong lookup index - compiles to wrong pubkey. Fix: regenerate client compile step from on-chain ALT read.
- Forgetting writable index flags - account meta permissions wrong. Fix: mark writable/signers in compiled message correctly.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Fewer accounts / merge ix | Simple programs | Unavoidable large metas |
| Multiple transactions | Non-atomic acceptable | Atomic swap required |
| Jito bundle atomicity | Multi-tx atomic landing | Single v0 sufficient |
| Remaining accounts pattern | On-chain dynamic metas | Client size still large |
FAQs
How many addresses per ALT?
Large capacity per table - extend in batches; multiple tables per tx allowed within limits.
Cost to create ALT?
Rent-exempt lamports for table account proportional to stored pubkeys plus tx fees.
Who can extend?
Authority set at creation - often deployer multisig.
Devnet ALT testing?
Same workflow - essential before mainnet large txs.
Relation to versioned transactions doc?
Can wallets sign v0?
Modern wallets support versioned transactions - test wallet matrix early.
ALT and priority fees?
Independent - size savings enable landing; fees still needed under congestion.
Close ALT?
Deactivate then close after cooldown to reclaim rent.
Hardcoded ALT in program?
Programs do not embed ALT - client supplies lookup in transaction message.
kit compile helpers?
Use kit transaction message builders with fetched lookup table accounts.
Related
- Versioned Transactions v0 - v0 format
- Address Lookup Tables (ALTs) - conceptual overview
- Transaction Assembly - ordering ixs
- Why Transactions Fail to Land - oversize drops
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.