Making Programs Immutable
Revoking upgrade authority makes program bytecode permanent on-chain. Users gain confidence that logic cannot change, but you lose the ability to patch bugs without deploying a new program ID and migrating state.
Recipe
Quick-reference recipe card - copy-paste ready.
# Irreversible - confirm program ID and hash first
solana program set-upgrade-authority <PROGRAM_ID> --final
solana program show <PROGRAM_ID> | grep AuthorityWhen to reach for this:
- Mature protocol maximizing trustlessness.
- Post-audit final release with no planned changes.
- Community requirement for immutable contracts.
- Completing governance timeline to freeze code.
Working Example
PROGRAM_ID=YourProgram1111111111111111111111111111111
# 1. Verify hash matches published attestation
solana-verify get-program-hash "$PROGRAM_ID" --url mainnet-beta
# compare to README attestation
# 2. Confirm multisig intended finality (if applicable)
# squads proposal: "Revoke upgrade authority"
# 3. Revoke authority (FINAL)
solana program set-upgrade-authority "$PROGRAM_ID" --final
# 4. Confirm immutable
solana program show "$PROGRAM_ID"
# Authority: (none)What this demonstrates:
--finalsets upgrade authority to null permanently.- No instruction can upgrade ELF after this point.
- Explorers show immutable status to users.
Deep Dive
How It Works
- Upgradeable loader checks authority pubkey on upgrade instructions.
- Null authority rejects all future upgrades.
- Program ID and user-facing addresses remain valid.
- New logic requires new program deployment + state migration.
Immutable vs Upgradeable
| Aspect | Immutable | Upgradeable |
|---|---|---|
| Trust | Highest code stability | Governance risk |
| Bug fix | New program + migrate | Same ID deploy |
| Authority | None | Multisig recommended |
| Timing | After audit + bake period | Default dev pattern |
bash Notes
# There is no CLI undo - only deploy new program if bug found
echo "Ensure incident playbooks cover migration to new program ID"Gotchas
- Premature revoke - Bug discovered after revoke. Fix: Bake period with multisig-only upgrades before
--final. - Wrong program ID - Revoke unintended deployment. Fix: Triple-check pubkey and
program showoutput. - Unverified bytecode - Immutable bad code forever. Fix:
solana-verifymatch before revoke. - Assuming migration is easy - User funds tied to old program PDAs. Fix: Plan migration tooling before immutability marketing.
- Proxy patterns - Immutable program with upgradeable delegate confuses users. Fix: Document architecture clearly.
- Hot wallet revoke - Compromised key revokes early. Fix: Multisig executes final revoke.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Multisig upgrade authority | Operational patch window | Absolute immutability marketing |
| Timelock + governance | Community oversight | Need instant bug fix |
| New versioned program | Breaking changes planned | Same-ID convenience |
FAQs
Can immutability be reversed?
No - on-chain permanent. Only deploy new program with new ID.
When should we revoke?
After audits, production bake, verifiable hash publication, and governance vote.
Does immutable affect accounts?
Program-owned accounts remain - only code changes are blocked.
Partial immutability?
Not on-chain - either authority exists or null. Use multisig as practical middle ground.
Immutable + verified hash?
Best practice - users verify hash then see immutable authority on explorer.
Client impact?
None if program ID unchanged - clients continue same pubkey.
Squads final revoke?
Create proposal executing set-upgrade-authority --final via multisig instruction.
Devnet testing?
Practice revoke on devnet disposable program before mainnet ceremony.
Legal/compliance angle?
Immutability statements should match on-chain authority field - verify in audits.
Emergency after revoke?
Deploy v2 program, migration instructions, user comms - no upgrade path on v1.
Related
- Program Upgrades - before immutability
- Governance-Gated Upgrades - multisig path
- Verifiable Builds - verify first
- Deployment Best Practices - authority policy
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.