Shipping a Solana program is not "upload a binary and walk away." It is a lifecycle: choose a program identity, fund rent for bytecode storage, stage ELF through the upgradeable loader, prove what you shipped, decide who may change it later, and plan what happens when a release goes wrong.
This page is the conceptual map for the section. Use it to place deploy flow, the upgradeable loader, upgrades, immutability, governance-gated authority, verifiable builds, and rollbacks on one continuum before you follow the focused recipe pages.
On modern Solana tooling (Agave 4.1.1 / Solana CLI 3.0.10), programs are almost always loaded with the BPF Upgradeable Loader. That model splits concerns:
A program account at the program ID is the stable, executable address clients call.
A program data account holds the ELF (SBF) bytes and the upgrade authority pubkey (or none).
A buffer account stages multi-step uploads so large deploys can resume and rent can be reclaimed on failure.
Deploy creates (or fills) those accounts from a built .so. Upgrade reuses the same program ID and replaces the ELF under authority control. Immutable means authority is permanently cleared so no further upgrade can succeed. Governance-gated means authority is a multisig or DAO vault, not a developer laptop key. Verifiable builds close the trust gap between public source and on-chain bytes. Rollback is operational: redeploy a previously attested artifact and re-verify the hash.
Account state your program owns (PDAs, vaults, config) is separate from program bytecode. Upgrading code does not rewrite user data layouts for you. Compatibility and migration are your responsibility.
Deployment is the process of putting executable bytecode on-chain so the runtime can invoke your program when a transaction lists your program ID. Clients such as Anchor 0.32.1, the Solana CLI, and @solana/kit 7.0.0 all target the same loader contracts: fund accounts, write bytes, mark executable, record who may upgrade.
Unlike traditional server deploys, there is no SSH session and no hidden process manager. The artifact is public, the authority is on-chain, and every future change is another signed transaction (or a hard stop if authority is gone).
The program ID is the pubkey of the program keypair (or the address you pass with --program-id). It must match declare_id! (Anchor) or your clients' hard-coded address. Changing program ID is a new deployment: clients, explorers, and PDA derivations that include the program id all move. Prefer same-ID upgrades when logic changes and state should stay under existing addresses.
Executable proxy at the program ID; points at ProgramData
ProgramData
ELF bytes + upgrade authority + last deploy metadata
Buffer
Temporary upload target for chunked writes during deploy/upgrade
solana program show <PROGRAM_ID> is the day-one inspection tool: data length, authority, ProgramData address, and last deploy slot. Treat that output as the control plane for release ops.
Whoever can sign as upgrade authority can replace production logic for every user of that program ID. That is stronger than a website deploy and closer to root on a shared binary. Hot wallets are fine for localnet and early devnet. Before meaningful TVL or public reliance, move authority to a controlled holder (typically Squads multisig or DAO execution path) or deliberately revoke it.
Losing the authority key without a recovery path freezes upgrades forever. That can be intentional (immutability) or accidental (ops failure). Design for the outcome you want.
Treat versions as a team contract. This guide assumes Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, Rust 1.91.1, and @solana/kit 7.0.0. Pin CLI, platform-tools, and Anchor like you pin Cargo.lock. Mismatched toolchains are a common cause of "it built on my laptop" hash mismatches under solana-verify.
Think of release ops as one pipeline with a few optional branches at the end: build, stage, land, verify, then either keep upgradeable (governed or not), freeze, or prepare to roll back.
anchor build wraps cargo build-sbf and emits IDL plus target/deploy/*.so for Anchor workspaces. Native crates use the SBF toolchain directly. Build on the pinned Agave/CLI stack so the ELF matches what validators expect.
For release candidates, prefer a reproducible path (solana-verify build in a controlled container) rather than a developer host binary alone. Host builds are fine for iteration; they are weak evidence for mainnet attestation.
solana program deploy path/to/program.so --program-id <keypair> funds rent for ProgramData proportional to bytecode size, writes via a buffer path under the hood when needed, and sets the deployer (or configured authority) as upgrade authority by default.
anchor deploy does the same within workspace config (Anchor.toml cluster and wallet). Always confirm cluster with solana config get before mainnet. Use --dry-run when you need a cost preview.
Failed mid-deploy leaves buffer rent behind. Close abandoned buffers or resume from a known buffer address. Details and recipes live in Deploying Programs and Deployment Basics.
Upgrade is not a separate magical opcode for product teams: you deploy a new .so targeting the existing program ID while holding upgrade authority. The loader replaces ProgramData contents; the program account address stays fixed. Clients keep calling the same pubkey. New transactions execute the new ELF after the upgrade lands.
Safe upgrades are a process, not a CLI flag:
Tag the commit and archive the .so + hash.
Run full tests (anchor test, negatives, migration paths).
Rehearse on devnet with the same pipeline.
Verify hash post-deploy.
Execute mainnet via governance if authority is gated.
Monitor and keep the previous artifact ready.
State layout breaks are the classic silent killer. If accounts gain fields or change meaning, ship versioned layouts and migration instructions. See Program Upgrades.
Users and auditors should not trust a tweet that "this is the code." solana-verify rebuilds under a controlled environment, hashes the executable, and compares against on-chain program data via RPC.
Minimum release evidence:
Field
Why it matters
Commit SHA
Source identity
Program ID
On-chain identity
Cluster
mainnet vs devnet
Executable / program hash
Byte-level attestation
Toolchain pins
Reproducibility
Gate CI so deploy jobs only ship the verified artifact. After deploy, re-fetch the program hash. Local match before upload is not enough if the wrong file was passed to program deploy.
Transferring upgrade authority to a Squads multisig (or DAO-controlled vault) turns bytecode change into a proposal: memo, hash, CI links, risk notes, and M-of-N signatures. Timelocks give the community time to react before execution.
Typical split:
Environment
Authority pattern
Local / CI
Ephemeral or team hot key
Devnet
Team key or light multisig
Mainnet pre-TVL
Multisig before public risk
Mainnet mature
Multisig + policy, or path to immutability
Never leave a "hidden" hot-wallet authority for emergencies while marketing multisig security. Explorers and program show will reveal the real authority. See Governance-Gated Upgrades.
solana program set-upgrade-authority <PROGRAM_ID> --final clears authority permanently. After that, no upgrade instruction can change the ELF. Trust in code stability rises; ability to patch critical bugs without a new program ID falls to zero.
Immutability is a product decision with ops consequences:
Do it only after audit, bake period, and verified hash attestation.
Pre-plan migration tooling if a future bug would require a new program and state move.
Prefer multisig-executed --final so a single compromised laptop cannot freeze the wrong artifact.
The runtime does not keep a stack of previous ELFs for one-click undo. Rollback means:
Detect and contain (pause risky UI flows if needed).
Dump current on-chain bytes for forensics (solana program dump).
Redeploy the last known-good .so under the same program ID (if still upgradeable).
Verify hash and smoke-test critical paths.
Communicate slot, signature, impact, and next steps.
If the program is already immutable, "rollback" becomes migrate users and liquidity to a new program ID, which is far more expensive. Archive every release artifact and hash in CI so rollback is possible. Full runbook patterns: Rollbacks & Incident Response.
Feature flags do not replace upgrades when the bug is in shipped code. They only reduce how often you touch bytecode for optional surfaces.
Rent scales with ProgramData size (roughly .so size). Close abandoned buffers so failed deploys do not leave rent stranded. Priority fees help landing under congestion but are secondary to rent for large programs.
Upgrades keep the program ID but can break IDL assumptions. Pin client IDLs and Codama/kit-generated types to the deployed version. Coordinate cutovers when instruction layouts change. @solana/kit 7.0.0 does not change loader semantics; release hygiene is operational.
Watch for unexpected upgrades or authority changes, hash drift from last attestation, error spikes after a deploy slot, and stuck governance during incidents. Monitoring without retained artifacts still leaves rollback blind.
Misconception: Deploy is one-time; upgrades are rare special cases.
Most production systems stay upgradeable for months. Design authority and verification on day one.
Misconception: The program account holds all the bytecode by itself.
ProgramData holds ELF and authority. The program account is the stable executable handle.
Misconception: Multisig makes upgrades automatically safe.
It raises the bar for unilateral change. Tests, verifiable builds, and devnet rehearsal still matter. Signers can approve a bad proposal.
Misconception: Verifiable builds are only marketing for open source.
They also stop you from deploying the wrong artifact and give incident responders ground truth for on-chain bytes.
Misconception: Immutable programs can still be hotfixed by the original team. --final is final at the loader. After that you need a new program and migration (unless you disclosed an indirection design).
Misconception: A Git tag alone guarantees rollback.
Archive the release .so and hash (or prove a reproducible rebuild of that tag). Git without the binary is not a rollback pack.
Misconception: Upgrading code migrates account data.
Only your instructions migrate state. New layouts on old accounts can brick paths or misread funds.
Misconception: Devnet deploy proves mainnet governance execution.
Devnet proves bytecode and smoke tests. Multisig UX, thresholds, and timelocks still need rehearsal.
Misconception: A hidden hot emergency key is harmless.
If it remains upgrade authority, it is the security model.
The on-chain program that owns upgradeable program accounts, stores ELF in ProgramData, and enforces upgrade authority on deploy and upgrade.
Does an upgrade change my program ID?
No. Same program pubkey; only executable bytes and related loader metadata change.
What is a buffer account?
A temporary account for ELF chunks during deploy or upgrade so large uploads can resume and failed attempts can reclaim rent.
How do I see who can upgrade a program?
solana program show <PROGRAM_ID> and read Authority. None means immutable.
When should I transfer authority to multisig?
Before mainnet capital or public dependency. Keep hot keys for local and early devnet only.
What does solana-verify prove?
That a controlled rebuild matches the on-chain executable hash when source, features, and locks match. It does not prove economic safety of the logic.
Can I undo set-upgrade-authority --final?
No. Plan migration to a new program ID if you must change logic after immutability.
How do mainnet rollbacks work?
If still upgradeable, redeploy a retained known-good .so to the same program ID via the authority path, then re-verify the hash. If immutable, migrate.
Is anchor deploy different from solana program deploy?
anchor deploy wraps workspace config and the same loader workflow. Native programs typically call the Solana CLI directly.
Why did my local hash not match CI?
Toolchain drift, unlocked deps, feature flags, or host vs container builds. Gate releases on solana-verify from a pinned environment.
Do clients need to change after an upgrade?
Not if instruction and account contracts stay compatible. Otherwise ship coordinated client/IDL updates with the upgrade.