Skip to main content
The Anchor framework uses Rust macros to reduce boilerplate code and simplify the implementation of common security checks required for writing Solana programs. The main macros found in an Anchor program include:
  • declare_id!: Specifies the program’s on-chain address
  • #[program]: Specifies the module containing the program’s instruction logic
  • #[derive(Accounts)]: Applied to structs to indicate a list of accounts required by an instruction
  • #[account]: Applied to structs to create custom account types for the program

Example program

Let’s examine a simple program that demonstrates the usage of the macros mentioned above to understand the basic structure of an Anchor program. The program below includes a single instruction called initialize that creates a new account (NewAccount) and initializes it with a u64 value.
use anchor_lang::prelude::*;

declare_id!("11111111111111111111111111111111");

#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        ctx.accounts.new_account.data = data;
        msg!("Changed data to: {}!", data);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    data: u64,
}

declare_id! macro

The declare_id! macro specifies the on-chain address of the program, known as the program ID.
use anchor_lang::prelude::*;

declare_id!("11111111111111111111111111111111");
By default, the program ID is the public key of the keypair generated at /target/deploy/your_program_name.json. To update the value of the program ID in the declare_id macro with the public key of the keypair in the /target/deploy/your_program_name.json file, run:
anchor keys sync
The anchor keys sync command is useful when cloning a repository where the program ID in the declare_id macro won’t match the one generated when you run anchor build locally.

#[program] attribute

The #[program] attribute annotates the module containing all the instruction handlers for your program. Each public function within this module corresponds to an instruction that can be invoked.
#[program]
mod hello_anchor {
    use super::*;
    
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        ctx.accounts.new_account.data = data;
        msg!("Changed data to: {}!", data);
        Ok(())
    }
    
    pub fn update(ctx: Context<Update>, data: u64) -> Result<()> {
        ctx.accounts.account.data = data;
        Ok(())
    }
}

Instruction parameters

Each instruction handler takes:
  1. Context: First parameter is always Context<T> containing validated accounts
  2. Additional parameters: Any additional instruction parameters
The Context<T> type provides access to:
  • accounts: The validated accounts
  • program_id: The program’s ID
  • remaining_accounts: Any additional accounts not specified in the #[derive(Accounts)] struct
  • bumps: PDA bump seeds for accounts using seeds constraint

#[derive(Accounts)] macro

The #[derive(Accounts)] macro is applied to structs to define the list of accounts required by an instruction.
#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Account constraints

Account constraints specify security checks and requirements:
  • init: Initialize a new account
  • mut: Mark account as mutable
  • payer: Specify who pays for account creation
  • space: Required space for the account
  • seeds and bump: For PDA validation
  • has_one: Check account fields match
  • constraint: Custom validation logic
See the account constraints reference for all available constraints.

#[account] attribute

The #[account] attribute is applied to structs to create custom account types that can be used with Anchor programs.
#[account]
pub struct NewAccount {
    data: u64,
}
This macro:
  • Implements AccountSerialize and AccountDeserialize traits
  • Adds an 8-byte discriminator to identify the account type
  • Implements the Owner trait to ensure the account is owned by the program

Space calculation

When creating accounts, you need to calculate the required space:
#[account]
#[derive(InitSpace)]
pub struct NewAccount {
    pub data: u64,      // 8 bytes
    pub owner: Pubkey,  // 32 bytes
    pub count: u32,     // 4 bytes
}  // Total: 44 bytes + 8 byte discriminator = 52 bytes
Use the InitSpace derive macro to automatically calculate space:
#[account(init, payer = user, space = 8 + NewAccount::INIT_SPACE)]
pub new_account: Account<'info, NewAccount>,

Complete example

Here’s a complete counter program demonstrating all the key components:
use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod counter {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.authority = ctx.accounts.authority.key();
        counter.count = 0;
        msg!("Counter initialized");
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count += 1;
        msg!("Counter incremented to {}", counter.count);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = authority, space = 8 + 32 + 8)]
    pub counter: Account<'info, Counter>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut, has_one = authority)]
    pub counter: Account<'info, Counter>,
    pub authority: Signer<'info>,
}

#[account]
pub struct Counter {
    pub authority: Pubkey,
    pub count: u64,
}

Next steps

Accounts

Learn about account types and validation

Instructions

Deep dive into instruction handlers

Build docs developers (and LLMs) love