Instruction Handlers
Instruction handlers are public functions inside #[program]. They receive Context<T> where T is the validated accounts struct, plus any Borsh-deserialized arguments.
Search across all documentation pages
Instruction handlers are public functions inside #[program]. They receive Context<T> where T is the validated accounts struct, plus any Borsh-deserialized arguments.
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(amount > 0, VaultError::InvalidAmount);
// business logic
Ok(())
}When to reach for this: You implement business logic for an on-chain instruction.
#[program]
pub mod vault {
use super::*;
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
let vault = &mut ctx.accounts.vault;
vault.total = vault.total.checked_add(amount).ok_or(VaultError::Overflow)?;
emit!(Deposited { amount, vault: vault.key() });
Ok(())
}
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, seeds = [b"vault"], bump = vault.bump)]
pub vault: Account<'info, VaultState>,
#[account(mut)]
pub depositor: Signer<'info>,
}What this demonstrates:
Context<Deposit> wraps accounts and program_idResult<()> propagates custom errorsctx.bumps exposes canonical bumps from seeds| Field | Use |
|---|---|
ctx.accounts | Mutable/immutable validated accounts |
ctx.program_id | Current program pubkey |
ctx.bumps | Map of bump seeds from constraints |
ctx.remaining_accounts | Extra accounts not in struct |
Keep handlers small; delegate to module functions for complex logic.
ctx.bumps.vault from seeds name.Result<()> or return data APIs.| Alternative | Use When | Don't Use When |
|---|---|---|
| Module helpers | Shared logic across handlers | Inline for tiny programs |
| return_data APIs | Return bytes to caller | Most instructions use accounts for output |
| Native instruction match arms | No Anchor | Anchor Context ergonomics |
0.32.1 throughout this section.
No. Use seeds constraints and CPI signing.
In your account struct field, set at initialization.
Use @solana/kit 7.0.0 with matching seed bytes.
Your Anchor program's declare_id address.
Not in seeds array; bump is separate parameter to find_program_address.
Compare logged keys; verify seeds and program id client-side.
Yes when holding data; fund with payer on init.
Yes with same signer seeds for each CPI.
See Related links for deeper handlers 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 19, 2026