The Accounts Struct
Every instruction declares an accounts struct with #[derive(Accounts)]. Anchor runs constraints before your handler executes, enforcing ownership, mutability, and relationships fail-closed.
Search across all documentation pages
Every instruction declares an accounts struct with #[derive(Accounts)]. Anchor runs constraints before your handler executes, enforcing ownership, mutability, and relationships fail-closed.
#[derive(Accounts)]
pub struct Transfer<'info> {
#[account(mut)]
pub from: Signer<'info>,
#[account(mut, constraint = to.owner == from.key())]
pub to: Account<'info, TokenAccount>,
pub token_program: Program<'info, Token>,
}When to reach for this: You design any instruction that touches on-chain accounts.
#[derive(Accounts)]
pub struct UpdateMetadata<'info> {
#[account(
mut,
seeds = [b"meta", authority.key().as_ref()],
bump = metadata.bump,
has_one = authority,
)]
pub metadata: Account<'info, Metadata>,
pub authority: Signer<'info>,
}
#[account]
pub struct Metadata {
pub authority: Pubkey,
pub bump: u8,
pub uri: String,
}What this demonstrates:
Signer, Account<T>, Program<T>) imply base checksbumps map is available in handlers for stored canonical bumps| Type | Validates |
|---|---|
Signer<'info> | Account signed the transaction |
Account<'info, T> | Owner is program, deserializes as T |
Program<'info, T> | Address matches program ID for T |
SystemAccount<'info> | Owned by system program |
UncheckedAccount<'info> | No automatic checks (use carefully) |
mut for writable accounts.owner, has_one, token constraints.address = expr, seeds/bump for PDAs.init, init_if_needed, close.address, owner, or constraint.mut.payer = signer and include system program.seeds + bump constraints.| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual validation in handler | Dynamic checks hard to express | Prefer declarative constraints for static rules |
| remaining_accounts | Variable account sets | Fixed layout known at compile time |
| AccountLoader for zero-copy | Large accounts | Small structs with Borsh |
0.32.1 for anchor-lang, Anchor CLI, and examples in this section.
Yes. Solana CLI 3.0.10 handles keypairs, airdrops, and solana program inspection.
target/idl/<program>.json in your workspace.
Yes, but every unchecked field needs explicit constraints or handler checks.
Use anchor test with Surfpool 0.12.0 or LiteSVM 0.6.x in CI.
Anchor account discriminator; do not strip it when sizing space.
Yes, or publish on-chain IDL so clients have a canonical source.
Run with logs; Anchor prints constraint name and account index.
Yes. This stack targets Agave validators with Solana CLI 3.0.10.
See sibling articles linked in Related for deeper accounts struct topics.
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.
Reviewed by Chris St. John·Last updated Jul 16, 2026