DEV Community

Cover image for My Solana Program Launch Checklist (Written the Day After I Actually Did It)
Lymah
Lymah Subscriber

Posted on

My Solana Program Launch Checklist (Written the Day After I Actually Did It)

Three weeks from now I will open a terminal, ready to ship another program to mainnet-beta, and I will pause. What was the order again?
Did the IDL go up before or after the authority transfer? Was there a flag that saved me from a stalled deploy last time?

This checklist exists because I just walked the entire path devnet to mainnet, deploy to IDL to frontend to error handling, and I wrote it down while the details are still fresh. It is the document I wish I had on day one of that process. Run it top to bottom before every mainnet launch.


Why a checklist at all?

A Solana mainnet deploy is full of irreversible steps. The wallet that signs the deploy quietly becomes the program's upgrade authority. A buffer account left mid-deploy can strand real SOL. A plain anchor build after a verifiable build can produce a different hash and break verification later.

None of these are complicated. They are all easy to forget under
pressure. A checklist is not a crutch; it is the habit that lets you ship calmly instead of improvising each time.


Phase 1: Pre-flight on devnet

Do all of this while mistakes are still free.

  • [ ] Every test passes against the final build. Run
    anchor build && cargo test --package <your-program> one last time. The binary you test must be the binary you ship.

  • [ ] End-to-end run on devnet. Call every instruction through the actual frontend, not just the test suite. The frontend is a different caller than LiteSVM and will surface different failure modes.

  • [ ] Produce a verifiable build. Run anchor build --verifiable. This pins the build environment so the on-chain bytecode can later be matched to your source code. Once you have this artifact, do not touch it with a plain anchor build or cargo build-sbf; those can produce a different hash and silently break verification.

  • [ ] Measure rent before you spend it. Run:

  solana rent $(wc -c < target/deploy/.so)
Enter fullscreen mode Exit fullscreen mode

Your deploy wallet must hold this amount plus a margin for
transaction fees. There is no airdrop on the mainnet.

  • [ ] Confirm your program ID is synced. Run anchor keys sync, then anchor build once more so the embedded ID and the artifact agree. A mismatched ID is the most common first-deploy failure.

  • [ ] Run your security checklist. Owner checks, signer checks, checked arithmetic, CPI program IDs — if you have not already run a pre-deploy audit, do it now. The account that drains is always the one you were sure about.


Phase 2: The deploy itself

This is the irreversible phase. Slow down here.

  • [ ] Switch CLI to mainnet-beta and confirm it.
  solana config set --url mainnet-beta
  solana config get
Enter fullscreen mode Exit fullscreen mode

Read the output. Confirm the RPC URL says mainnet. Do not skip this. A devnet deploy "succeeding" against mainnet SOL is a real mistake that happens to real developers.

  • [ ] Check your wallet balance one more time.
  solana balance
Enter fullscreen mode Exit fullscreen mode

Confirm it covers rent plus fees. If you are short, fund the wallet now; there is no airdrop here.

  • [ ] Deploy through a dedicated RPC with a priority fee. The public mainnet RPC is rate-limited enough that a large deploy can stall. Use a Helius or QuickNode free-tier endpoint and add a priority fee to give your transactions a better chance of landing:
  anchor program deploy \
    --provider.cluster "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY" \
    -- --with-compute-unit-price 10000 --use-rpc
Enter fullscreen mode Exit fullscreen mode

The --with-compute-unit-price flag pays extra micro-lamports per compute unit to nudge validators to include your transactions sooner.

  • [ ] If the deploy stalls, do not re-run from scratch. A deploy is not atomic; it uploads through a temporary buffer account. If it is interrupted, your SOL is in that buffer, not lost. Check for it:
  solana program show --buffers
Enter fullscreen mode Exit fullscreen mode

Resume with --buffer <BUFFER_KEYPAIR> or recover the rent with
solana program close <BUFFER_ADDRESS>. Re-running from scratch leaks SOL on each attempt.


Phase 3: Authority and verification, right after deploy

Do this before you do anything else. You want to know the program
landed correctly while the deploy is still fresh in your mind.

  • [ ] Confirm the program is live.
  solana program show  --url mainnet-beta
Enter fullscreen mode Exit fullscreen mode

Read every field: program ID, owner (BPFLoaderUpgradeab1e...
means upgradeable), upgrade authority, data length, balance. Here is the output from my vault program on devnet:

Program Id: 9efHREoHuDSCmEsFsrnX2rmZEoZ1dPc4n15q8V8YNBzh
Owner: BPFLoaderUpgradeab1e11111111111111111111111
Authority: ETVgewbsk8EKDWFheVxbyWQyVgqsGukrntXjb2VL5Umq
Data Length: 108976 bytes
Balance: 0.75967704 SOL
Enter fullscreen mode Exit fullscreen mode
  • [ ] Make a deliberate decision about upgrade authority. Right now the authority is the wallet that signed the deploy, a single key on your laptop. You have three options:

    • Leave it as-is (acceptable for a small personal program, not for anything with users' funds)
    • Transfer to a Squads multisig (the professional choice, every upgrade requires multiple signers):
    solana program set-upgrade-authority <PROGRAM_ID> \
      --new-upgrade-authority <SQUADS_MULTISIG_ADDRESS>
Enter fullscreen mode Exit fullscreen mode
  • Freeze it permanently with --final (irreversible, for a program you never intend to upgrade):
    # Only run this if you mean it. There is no undo.
    solana program set-upgrade-authority <PROGRAM_ID> --final
Enter fullscreen mode Exit fullscreen mode

I chose to keep the authority on a keypair I control for the devnet program, and I practiced transferring it to a throwaway key and back before touching any production authority. The practice run is worth doing; the command feels different when it is real.

  • [ ] Publish the IDL on-chain.
  anchor idl init -f target/idl/<program>.json <PROGRAM_ID> \
    --provider.cluster "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY"
Enter fullscreen mode Exit fullscreen mode

Without this, anyone who tries to interact with your program
programmatically has to hand-pack byte buffers. The IDL makes your program self-describing; the interface travels with the program.

  • [ ] Fetch the IDL back and verify it round-trips.
  anchor idl fetch <PROGRAM_ID> \
    --provider.cluster "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY" \
    -o fetched-idl.json
  diff target/idl/<program>.json fetched-idl.json
Enter fullscreen mode Exit fullscreen mode

If the diff is empty, the IDL on-chain matches your local copy.

  • [ ] Regenerate the typed client.
  npx codama run js
Enter fullscreen mode Exit fullscreen mode

The client in clients/js/src/generated/ is now pointing at the mainnet program. Any frontend that imports it gets the mainnet interface automatically.


Phase 4: Frontend and going live

  • [ ] Update the program ID in the frontend. If your React app hardcodes a devnet program ID anywhere, swap it for mainnet. With the Codama-generated client, the program ID lives in clients/js/src/generated/programs/ — update it there and every call in the app follows.

  • [ ] Switch the frontend cluster to mainnet.
    In src/providers.tsx (or wherever your SolanaProvider lives), change the endpoint from devnet to mainnet:

  endpoint: "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY"
Enter fullscreen mode Exit fullscreen mode
  • [ ] Connect a real wallet and confirm the balance reads correctly. Open the app, connect Phantom or Solflare (set to mainnet), and confirm the address and balance on screen match what you see in the wallet. A mismatch here almost always means a cluster mismatch: app on mainnet, wallet still on devnet, or vice versa.

  • [ ] Walk every error scenario once more. With real SOL at stake, confirm your error classifier still produces calm messages:

    • Cancel the wallet popup → "Transaction cancelled, nothing was sent"
    • Submit with too little SOL → "Not enough SOL to cover amount + fee"
    • Disconnect mid-flow → "Wallet not connected, reconnect and try again"

The classifier you built on Day 89 does not care which cluster it is on, but the error messages become more important when the funds are real.

  • [ ] Announce the launch. Tell people it is live. Post the program ID, the Explorer link, and where to report issues. A program that nobody knows about is not a launch.

  • [ ] Write down where users report problems. A GitHub issues link, a Discord channel, a contact email — anything specific. "DM me" is not a support channel.


The thing that surprised me most

I expected the deploy to be the hard part. It was not. The deploy
itself took a few minutes and stalled once on the public RPC (I used --use-rpc after that and it landed cleanly).

The part I did not expect was how much weight the upgrade authority carries. The wallet that signs the deploy quietly becomes the key that controls every future version of that program. There is no warning banner, no confirmation prompt — just a field in solana program show that says who holds it. If that file leaks, an attacker can rewrite your program. If it is lost, the program can never be upgraded again.

That single field deserves a deliberate decision, not a default. The checklist above is built around making that decision explicitly rather than noticing it three weeks later.


Proof: program live on devnet

Program Id: 9efHREoHuDSCmEsFsrnX2rmZEoZ1dPc4n15q8V8YNBzh
Owner: BPFLoaderUpgradeab1e11111111111111111111111
ProgramData Address: 6kvYu7atWDzcHo8VxPZV3T2uQ77TycSd5zWMSD5qFVGG
Authority: ETVgewbsk8EKDWFheVxbyWQyVgqsGukrntXjb2VL5Umq
Last Deployed In Slot: 476201752
Data Length: 108976 (0x1a9b0) bytes
Balance: 0.75967704 SOL
Enter fullscreen mode Exit fullscreen mode

Part of *#100DaysOfSolana**

Top comments (0)