Guide

How to deploy a Solana program

On Solana, executable logic lives in programs — the chain's equivalent of smart contracts. A token swap, an NFT mint, a game settlement rule, or a payment verifier is all compiled Rust (or C) into BPF bytecode, uploaded to an on-chain account, and invoked by transactions. Deploying that bytecode is a distinct step from writing it: you need a funded wallet, a reliable RPC endpoint, a program keypair, and clarity about who can upgrade the code later. This guide walks through the full path from devnet practice to a cautious mainnet launch.

What you are deploying

A Solana program is not stored inside a user's wallet. It is a special executable account owned by the BPF Loader — a built-in program that knows how to run your bytecode when other transactions call invoke on your program ID. Users and your frontend never send raw bytecode; they send instructions (function selectors plus serialized arguments) to your program's public key.

Three ideas matter before you run solana program deploy:

Most tutorials deploy to devnet first — free test SOL, same loader semantics, no financial risk. See our devnet vs mainnet guide if you are unsure which cluster your wallet points at.

Prerequisites

Before deploying, assemble the toolchain and a funded deployer wallet:

Check your config: solana config get should show the cluster, RPC URL, and keypair path you expect. A wrong cluster is the fastest way to burn real SOL on a test deploy or wonder why devnet faucets fail on mainnet.

Generate and secure your program keypair

Each program needs its own keypair. The public key becomes the program ID clients call.

solana-keygen new -o target/deploy/my_program-keypair.json

Back up this file. If you deploy without specifying a keypair, the CLI generates one — but Anchor projects usually commit the path in Anchor.toml under [programs.devnet] or [programs.mainnet]. For mainnet, store keypairs offline or in a secrets manager; anyone with the file can impersonate upgrade authority if you assign it to that key.

Anchor can sync the declared program ID into your source: anchor keys sync updates declare_id! macros to match the keypair on disk.

Deploy with the Solana CLI (native Rust)

After cargo build-sbf produces target/deploy/my_program.so, upload it:

solana program deploy \
  target/deploy/my_program.so \
  --program-id target/deploy/my_program-keypair.json \
  --url devnet

The CLI chunks the binary, creates or resizes the program account, and sets the upgrade authority to your default keypair unless you pass --upgrade-authority. On success you get a transaction signature and the program ID printed to stdout.

Verify on-chain

Our Solscan walkthrough helps decode the deploy transaction if something looks off.

Deploy with Anchor

Anchor is the dominant framework for Solana programs: account validation macros, IDL generation, and integrated deploy scripts. Typical workflow:

Anchor's deploy command is a wrapper around the same BPF loader mechanics as the raw CLI. The value is consistency: your tests, IDL, and TypeScript client all reference the same program name. For a frontend-only product that never ships custom bytecode — e.g. accepting SOL via Solana Pay — you may not need Anchor at all; see accept Solana payments for a server-verified flow without deploying programs.

Upgrade authority and program upgrades

Solana's upgradeable loader lets you patch bugs after launch. The wallet listed as upgrade authority can:

Revoking upgrade authority makes the program immutable — required for some audits and trust models (users know the rules cannot change). Do this only when you are certain: there is no undo without deploying an entirely new program ID and migrating user state.

Multisig upgrade authorities (e.g. Squads) are common for teams: the program ID stays fixed while three-of-five signers must approve each upgrade.

Rent, size, and compute limits

Program accounts pay rent exemption upfront — SOL locked proportional to bytecode size. Large programs cost more to deploy but do not incur ongoing rent while exempt. Deployment transactions also consume compute units; congested mainnet may need a priority fee so the deploy lands in the next few slots.

Solana imposes a max program size (on the order of hundreds of KB per deploy chunking rules). If your binary is huge, split logic across multiple programs or trim dependencies. Profile with ls -lh target/deploy/*.so before mainnet.

Devnet checklist

Run through this on devnet before touching mainnet:

Step Why it matters
Point RPC and wallet at devnet Avoids accidental mainnet spend
Airdrop or faucet SOL to deployer Deploy + account creation need fees
Deploy + program show Confirms bytecode landed
Integration tests / manual invoke Catches account constraint bugs early
Practice upgrade + rollback Builds muscle memory before production
Document program ID + authority keys On-call debugging without guesswork

Moving to mainnet

Mainnet deployment is the same commands with a different cluster URL and real SOL. Extra precautions:

Frontend and indexer teams need the mainnet program ID, IDL, and cluster commitment level (confirmed vs finalized) before launch. Our Garden Dice build log shows how a production site wires RPC and verification without exposing keys — useful context even if your program is unrelated to games.

Common deployment errors

Related guides