The #[program] Module
The #[program] attribute macro generates Solana's entrypoint, instruction dispatch, and discriminator checks. Your public functions become on-chain instructions.
Search across all documentation pages
The #[program] attribute macro generates Solana's entrypoint, instruction dispatch, and discriminator checks. Your public functions become on-chain instructions.
#[program]
pub mod my_program {
use super::*;
pub fn initialize(ctx: Context<Initialize>, amount: u64) -> Result<()> {
ctx.accounts.config.amount = amount;
Ok(())
}
}When to reach for this: You add or rename an instruction exposed to clients.
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod escrow {
use super::*;
pub fn initialize(ctx: Context<Initialize>, amount: u64) -> Result<()> {
let escrow = &mut ctx.accounts.escrow;
escrow.amount = amount;
escrow.authority = ctx.accounts.authority.key();
Ok(())
}
pub fn release(ctx: Context<Release>) -> Result<()> {
require!(ctx.accounts.authority.key() == ctx.accounts.escrow.authority, EscrowError::Unauthorized);
// transfer logic ...
Ok(())
}
}
#[account]
pub struct Escrow {
pub amount: u64,
pub authority: Pubkey,
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = authority, space = 8 + Escrow::INIT_SPACE)]
pub escrow: Account<'info, Escrow>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Release<'info> {
#[account(mut, has_one = authority)]
pub escrow: Account<'info, Escrow>,
pub authority: Signer<'info>,
}What this demonstrates:
pub fn is one instruction with a unique discriminator#[derive(Accounts)] typesResult<()> for fallible instructions| Part | Role |
|---|---|
Context<T> | Validated accounts for this instruction |
| Extra args | Borsh-deserialized instruction data |
Result<()> | Success or custom program error |
init - Conflicts with reserved patterns in some tooling. Fix: Use initialize instead.#[derive(Accounts)] at module root.use super::* - Types not in scope inside module. Fix: Add the import at top of program module.Context<StructName>.Result<()> unless returning data explicitly.
| Alternative | Use When | Don't Use When |
|---|---|---|
Native entrypoint! + match | Minimal binary size | You want declarative account validation |
| Pinocchio dispatch | Lowest CU overhead | You need Anchor IDL and macros |
| Multiple #[program] modules | Not supported in one crate | Split into separate program crates |
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 program module 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