One command for Claude Code, Cursor, Codex, Windsurf and other agents — installs from the upstream repo (current HEAD; it ships 6 skills — pick deployment when prompted).
Drop the mirrored SKILL.md into your skills directory. Global (all projects):
Or scoped to the current project:
The skill is mirrored as plain markdown — tell your agent:
Or have the skills CLI generate a one-shot prompt (pipe it straight into your agent):
Or pull the raw file into a terminal session:
Copy the skill directory straight from GitHub:
Skill contents
Deployment Workflows
Deployment Strategy Overview
| Environment | Purpose | Commitment | Upgrades |
|---|---|---|---|
| localnet | Development | processed | Frequent, no restrictions |
| devnet | Testing | confirmed | Frequent, test multisig |
| testnet | Staging | confirmed | Controlled, production-like |
| mainnet | Production | finalized | Rare, full security review |
Pre-Deployment Checklist
Code Quality
- All tests passing (unit, integration, fuzz)
- Security audit completed (for mainnet)
- Code review approved
- No
unwrap()orexpect()in program code - All arithmetic uses checked operations
Build Verification
- Verifiable build successful
- Binary hash matches expected
- IDL generated and committed
- Client SDK generated and tested
Security Review
- All accounts validated
- CPI targets hardcoded
- PDA bumps stored
- Accounts reloaded after CPIs
- Reentrancy considered
Documentation
- CHANGELOG updated
- Migration guide if breaking changes
- User-facing documentation updated
Devnet Deployment
First Deployment
# 1. Build with verifiable flag
anchor build --verifiable
# 2. Get program keypair
solana-keygen new -o target/deploy/my_program-keypair.json
# 3. Airdrop devnet SOL
solana airdrop 2 --url devnet
# 4. Deploy to devnet
anchor deploy --provider.cluster devnet
# 5. Verify deployment
solana program show <PROGRAM_ID> --url devnet
Upgrade Deployment
# 1. Build new version
anchor build --verifiable
# 2. Verify buffer before upgrade
solana program write-buffer target/deploy/my_program.so --url devnet
solana program show <BUFFER_ADDRESS> --url devnet
# 3. Deploy upgrade
anchor upgrade target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--provider.cluster devnet
# 4. Close old buffers to reclaim SOL
solana program close --buffers --url devnet
IDL Update
# Update IDL on-chain (required for explorer parsing)
anchor idl upgrade --filepath target/idl/my_program.json \
--provider.cluster devnet \
<PROGRAM_ID>
Mainnet Deployment
Pre-Mainnet Verification
# 1. Full test suite
cargo test --all
# 2. Fuzz testing (critical paths)
trident fuzz run fuzz_0 --iterations 50000
# 3. Build verification
anchor build --verifiable
anchor verify <PROGRAM_ID> --provider.cluster devnet
# 4. Audit tool scan
soteria -analyzeAll .
Mainnet First Deploy
# 1. Ensure sufficient SOL (deployment costs ~2-5 SOL depending on program size)
solana balance --url mainnet
# 2. Build verifiable
anchor build --verifiable
# 3. Deploy with confirmation prompts
anchor deploy --provider.cluster mainnet
# 4. Immediately verify on-chain
anchor verify <PROGRAM_ID> --provider.cluster mainnet
# 5. Publish IDL
anchor idl init --filepath target/idl/my_program.json \
--provider.cluster mainnet \
<PROGRAM_ID>
Mainnet Upgrade (With Multisig)
For production programs, use a multisig upgrade authority:
# 1. Write new buffer (anyone can do this)
solana program write-buffer target/deploy/my_program.so \
--url mainnet \
--buffer-authority <MULTISIG_PDA>
# 2. Verify buffer contents
solana program dump <BUFFER_ADDRESS> buffer_dump.so --url mainnet
diff <(xxd target/deploy/my_program.so) <(xxd buffer_dump.so)
# 3. Create upgrade proposal via multisig UI (e.g., Squads)
# Members review and approve
# 4. Execute upgrade after threshold reached
# (Handled by multisig program)
# 5. Verify post-upgrade
anchor verify <PROGRAM_ID> --provider.cluster mainnet
Multisig Setup (Squads v4)
Creating a Squad for Program Authority
import { Squads } from "@sqds/multisig";
async function createProgramSquad() {
const squads = new Squads({ connection, wallet });
// Create multisig with 2-of-3 threshold
const multisigPda = await squads.createMultisig({
threshold: 2,
members: [
{ pubkey: member1.publicKey, permissions: { vote: true, execute: true } },
{ pubkey: member2.publicKey, permissions: { vote: true, execute: true } },
{ pubkey: member3.publicKey, permissions: { vote: true, execute: false } },
],
});
console.log("Multisig created:", multisigPda.toString());
return multisigPda;
}
Transferring Upgrade Authority to Multisig
# Transfer program upgrade authority to multisig
solana program set-upgrade-authority <PROGRAM_ID> \
--new-upgrade-authority <MULTISIG_PDA> \
--url mainnet
Creating Upgrade Proposals
async function proposeUpgrade(
squads: Squads,
multisigPda: PublicKey,
programId: PublicKey,
bufferAddress: PublicKey
) {
const transaction = await squads.createTransaction({
multisig: multisigPda,
instructions: [
SystemProgram.createUpgradeInstruction({
programId,
bufferAddress,
upgradeAuthority: multisigPda,
spillAccount: treasury,
}),
],
});
console.log("Upgrade proposal created:", transaction.toString());
}
Upgrade Authority Staging
Stage the path to immutability rather than freezing at launch:
- Launch → ~3 months — keep upgrade authority on a secured deployer key (hardware wallet). Bugs surface early; you need the ability to ship fixes fast.
- ~3 months post-launch — transfer authority to the Squads multisig (above). Removes single-key risk once the program is stable.
- Post-audit, battle-tested — freeze:
solana program set-upgrade-authority <PROGRAM_ID> --final. Irreversible and removes any rollback path — only after extensive mainnet history and a completed audit.
CI/CD Pipeline
GitHub Actions Workflow
name: Solana Program CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
SOLANA_VERSION: "2.1.0"
ANCHOR_VERSION: "0.31.1"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Solana
uses: solana-labs/solana-actions/setup@v1
with:
solana-version: ${{ env.SOLANA_VERSION }}
- name: Setup Anchor
run: |
cargo install --git https://github.com/coral-xyz/anchor anchor-cli --tag v${{ env.ANCHOR_VERSION }}
- name: Install dependencies
run: yarn install
- name: Build
run: anchor build --verifiable
- name: Test
run: anchor test
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: program-artifacts
path: |
target/deploy/*.so
target/idl/*.json
deploy-devnet:
needs: test
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: devnet
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: program-artifacts
- name: Setup Solana
uses: solana-labs/solana-actions/setup@v1
- name: Configure keypair
run: |
echo "${{ secrets.DEVNET_DEPLOYER_KEYPAIR }}" > deployer.json
solana config set --keypair deployer.json --url devnet
- name: Deploy to devnet
run: |
anchor deploy --provider.cluster devnet
- name: Verify deployment
run: |
anchor verify ${{ vars.PROGRAM_ID }} --provider.cluster devnet
deploy-mainnet:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: mainnet
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: program-artifacts
- name: Write buffer
run: |
# Only write buffer - manual multisig approval required
echo "${{ secrets.MAINNET_BUFFER_KEYPAIR }}" > buffer.json
solana program write-buffer target/deploy/my_program.so \
--url mainnet \
--keypair buffer.json
- name: Output buffer address
id: buffer
run: echo "::set-output name=address::$(cat buffer-address.txt)"
- name: Create PR comment
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 Buffer written to mainnet: \`${{ steps.buffer.outputs.address }}\`\n\nApprove upgrade via Squads multisig.`
})
Rollback Procedures
Devnet Rollback
# Redeploy previous version
anchor deploy --provider.cluster devnet \
--program-id <PROGRAM_ID> \
target/deploy/my_program_v1.so
Mainnet Rollback
- Immediate: If caught quickly, create emergency multisig proposal for rollback
- Planned: Keep previous verified buffer, create upgrade proposal to previous version
- Emergency freeze: If program has freeze capability, pause operations while preparing rollback
Freeze Pattern (Program Design)
#[account]
pub struct GlobalState {
pub authority: Pubkey,
pub is_frozen: bool, // Emergency stop
}
// In each instruction
pub fn some_instruction(ctx: Context<SomeInstruction>) -> Result<()> {
require!(!ctx.accounts.global_state.is_frozen, ErrorCode::ProgramFrozen);
// ... instruction logic
}
Environment Configuration
.env.development
SOLANA_RPC_URL=http://localhost:8899
SOLANA_WS_URL=ws://localhost:8900
PROGRAM_ID=<LOCAL_PROGRAM_ID>
.env.devnet
SOLANA_RPC_URL=https://api.devnet.solana.com
SOLANA_WS_URL=wss://api.devnet.solana.com
PROGRAM_ID=<DEVNET_PROGRAM_ID>
.env.mainnet
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
SOLANA_WS_URL=wss://api.mainnet-beta.solana.com
PROGRAM_ID=<MAINNET_PROGRAM_ID>
# Consider premium RPC providers for production:
# - Helius
# - QuickNode
# - Triton
Deployment Cost Estimation
| Action | Approximate Cost |
|---|---|
| Deploy small program (<100KB) | ~1.5 SOL |
| Deploy medium program (100-500KB) | ~3-5 SOL |
| Deploy large program (>500KB) | ~5-10 SOL |
| Upgrade (buffer write) | Same as deploy |
| IDL init/upgrade | ~0.01 SOL |
| Close old buffers | Returns ~90% of rent |
Tip: Close unused buffers after upgrades to reclaim SOL:
solana program close --buffers --url mainnet
Post-Deployment Verification
On-Chain Verification
# Verify program binary matches source
anchor verify <PROGRAM_ID> --provider.cluster mainnet
# Check program authority
solana program show <PROGRAM_ID> --url mainnet
# Verify IDL
anchor idl fetch <PROGRAM_ID> --provider.cluster mainnet > fetched_idl.json
diff target/idl/my_program.json fetched_idl.json
Functional Verification
# Run smoke tests against deployed program
anchor test --skip-build --provider.cluster devnet
# Monitor logs for first transactions
solana logs <PROGRAM_ID> --url devnet
Best Practices Summary
- Always use verifiable builds for production deployments
- Use multisig for mainnet upgrade authority
- Test on devnet before mainnet
- Keep deployment keys secure (HSM or multisig)
- Document every deployment with version and hash
- Have a rollback plan before deploying
- Monitor post-deployment for anomalies
- Close old buffers to reclaim SOL