Feature Flags & cfg
Use Cargo features and #[cfg(feature = ...)] to gate debug logs, dev-only instructions, and cluster-specific code in Anchor programs.
Recipe
[features]
default = []
debug-log = []
devnet-only = []#[cfg(feature = "debug-log")]
msg!("debug");When to reach for this: You need different builds for dev vs mainnet or optional diagnostics.
Working Example
#[cfg(feature = "devnet-only")]
#[program]
pub mod my_program {
pub fn airdrop_test_tokens(ctx: Context<Airdrop>) -> Result<()> {
// only compiled when feature enabled
Ok(())
}
}
#[cfg(not(feature = "devnet-only"))]
#[program]
pub mod my_program {
// production instructions only
}What this demonstrates:
- Features control compile-time inclusion
- Smaller mainnet binary without dev ix
- cfg on modules requires care with #[program]
- Document features in README
Deep Dive
Anchor Caveat
Splitting #[program] modules by cfg changes IDL between builds. Prefer separate dev crates or instructions behind admin keys instead of shipping dev ix to mainnet.
cluster feature pattern
Use constants in Anchor.toml / build scripts rather than multiple #[program] mods when possible.
Gotchas
- Different IDL per feature set - Client confusion.. Fix: One release profile for mainnet.
- Accidentally enabling devnet-only on mainnet - Extra attack surface.. Fix: CI forbids feature combo.
- cfg in account structs - IDL layout drift.. Fix: Keep account layout stable across builds.
- Debug logs feature left on - CU waste.. Fix: Default features empty.
- Two #[program] mods mistake - Compile errors.. Fix: Single program module per build.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Separate dev program crate | Clear separation | Feature flags in one crate |
| Runtime admin gate | Same binary | Compile-time removal |
FAQs
Anchor version?
0.32.1 across advanced topics.
When to use zero_copy?
Large fixed layouts when Borsh CU too high.
Is realloc reversible?
Not easily; plan forward growth.
Are remaining accounts in IDL?
No; document separately.
declare_program! needs what?
Callee IDL JSON at compile time.
Can Anchor CPI to Pinocchio?
Yes with correct account metas.
Feature flags and IDL?
Avoid different IDL per feature on mainnet.
How to measure CU?
LiteSVM, Surfpool, devnet simulation.
Custom account types common?
No; last resort.
Next steps?
See Related links for features.
Related
- Logging & CU Cost - debug logs
- Program Upgrades - releases
- Making Programs Immutable - final deploy
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.