Creating & Closing Accounts
Account creation allocates space, assigns an owner, and funds rent-exemption. Closing reclaims lamports. realloc grows or shrinks data in place.
Search across all documentation pages
Account creation allocates space, assigns an owner, and funds rent-exemption. Closing reclaims lamports. realloc grows or shrinks data in place.
// Create
#[account(init, payer = payer, space = 8 + MyData::INIT_SPACE)]
pub data: Account<'info, MyData>,
// Grow
#[account(mut, realloc = new_size, realloc::payer = payer, realloc::zero = false)]
pub data: Account<'info, MyData>,
// Close
#[account(mut, close = receiver)]
pub data: Account<'info, MyData>,When to reach for this:
use anchor_lang::prelude::*;
#[program]
pub mod lifecycle {
use super::*;
pub fn create(ctx: Context<Create>, label: String) -> Result<()> {
ctx.accounts.data.authority = ctx.accounts.payer.key();
ctx.accounts.data.label = label;
Ok(())
}
pub fn expand(ctx: Context<Expand>, extra: u32) -> Result<()> {
ctx.accounts.data.extra = extra;
Ok(())
}
pub fn close_account(ctx: Context<CloseData>) -> Result<()> {
Ok(())
}
}
#[account]
#[derive(InitSpace)]
pub struct MyData {
pub authority: Pubkey,
#[max_len(20)]
pub label: String,
pub extra: u32,
}
#[derive(Accounts)]
pub struct Create<'info> {
#[account(init, payer = payer, space = 8 + MyData::INIT_SPACE)]
pub data: Account<'info, MyData>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Expand<'info> {
#[account(
mut,
realloc = 8 + MyData::INIT_SPACE,
realloc::payer = payer,
realloc::zero = false,
)]
pub data: Account<'info, MyData>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct CloseData<'info> {
#[account(mut, close = receiver, has_one = authority)]
pub data: Account<'info, MyData>,
pub authority: Signer<'info>,
#[account(mut)]
pub receiver: SystemAccount<'info>,
}What this demonstrates:
init CPIs to System Program for allocation + rent transferrealloc may require additional lamports from realloc::payerclose zeros data and sends all lamports to receiverspace bytesclose sets lamports to 0 and assigns owner to System Programinit without system_program - compile/runtime failure. Fix: always include Program<'info, System>.mut on payer for realloc - insufficient funding. Fix: mark payer mut when realloc may cost lamports.| Alternative | Use When | Don't Use When |
|---|---|---|
init_if_needed | Idempotent onboarding | Strict one-time creation security |
| Manual System CPI | Native programs without Anchor | Anchor projects (use macros) |
| New account migration | Breaking layout changes | Minor field additions |
realloc | Modest size growth | Large dataset changes (new PDA) |
CPI to System Program create_account with space, owner, and lamports from payer.
Your program via close constraint - typically requiring authority signer.
The account specified in close = receiver.
When account data grows beyond originally allocated space.
Yes, if larger size requires higher rent-exempt minimum. Payer funds difference.
Yes. Program signs if needed; lamports go to receiver.
Creates account only if it doesn't exist - useful for ATAs-like patterns with care.
Same address can be re-initialized if recreated with init - treat as new account.
Multiple close constraints in one instruction - watch CU limits.
Not automatically. Add emit! for indexers.
System-owned empty accounts can be drained; program-owned require program instruction.
Whether new bytes are zeroed. false preserves existing data during growth.
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