Setting Up Anchor for Development (Solana)
Solana development without Anchor is working directly with low-level Solana Program Library and manual account data deserialization via borsh. Anchor adds macros, code generation, and IDL (Interface Definition Language). But setting up the environment from scratch takes longer than expected — tool versions conflict, Anchor must be built compatible with a specific solana-cli version.
What Goes Wrong on First Setup
Version incompatibility. Anchor 0.30.x requires Solana CLI 1.18.x. Anchor 0.29.x worked with 1.17.x. Installing latest Anchor + latest Solana — nearly guaranteed conflict on anchor build. Error error[E0308]: mismatched types in generated code — usually exactly this.
Compatible versions as of April 2025:
| Anchor | Solana CLI | Rust |
|---|---|---|
| 0.30.1 | 1.18.17 | 1.75+ |
| 0.29.0 | 1.17.34 | 1.72+ |
| 0.28.0 | 1.16.x | 1.70+ |
avm (Anchor Version Manager) solves the version switching problem:
cargo install --git https://github.com/coral-xyz/anchor avm --force
avm install 0.30.1
avm use 0.30.1
Solana Tool Suite is installed separately and also requires exact version specification:
sh -c "$(curl -sSfL https://release.anza.xyz/v1.18.17/install)"
After installation — verify via solana --version and anchor --version. If versions don't match expectations — PATH isn't updated.
Anchor Project Structure
After anchor init my-program you get:
my-program/
├── programs/
│ └── my-program/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs # program entry point
├── tests/
│ └── my-program.ts # Mocha/Chai tests
├── app/ # optional, frontend
├── migrations/
│ └── deploy.ts
├── Anchor.toml # project config
└── package.json
Anchor.toml is the central config. It specifies:
-
[programs.localnet]/[programs.mainnet]— deployed program addresses -
[provider]— cluster (localnet/devnet/mainnet) and wallet path -
[scripts]— migration and test commands
Cluster setup. For local development use solana-test-validator:
solana-test-validator --reset
# in separate terminal:
anchor test --skip-local-validator # if validator already running
# or simply:
anchor test # starts validator automatically
IDL and Client Integration
The main value of Anchor is automatic IDL (JSON schema of the program) generation on anchor build. IDL describes accounts, instructions, types, events. TypeScript client is generated based on IDL.
import { Program, AnchorProvider } from "@coral-xyz/anchor";
import { MyProgram, IDL } from "./target/types/my_program";
const provider = AnchorProvider.env();
const program = new Program<MyProgram>(IDL, provider);
// Instruction call
await program.methods
.initialize(new BN(1000))
.accounts({
myAccount: myAccountKp.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([myAccountKp])
.rpc();
Types are generated automatically from IDL — no manual interface descriptions. On program change — recompile and TypeScript types update.
Account constraints. Anchor macros #[account] with annotations are key:
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = user,
space = 8 + MyAccount::INIT_SPACE,
seeds = [b"my-seed", user.key().as_ref()],
bump
)]
pub my_account: Account<'info, MyAccount>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
seeds + bump — automatic PDA (Program Derived Address) derivation and verification. Anchor verifies bump on each call — this prevents attacks via PDA substitution.
Testing
Tests are written in TypeScript via Mocha (built into Anchor). anchor test compiles the program, runs localnet, deploys the program, and runs tests.
it("initializes account", async () => {
const [myPda] = PublicKey.findProgramAddressSync(
[Buffer.from("my-seed"), user.publicKey.toBuffer()],
program.programId
);
await program.methods
.initialize(new BN(1000))
.accounts({ myAccount: myPda, user: user.publicKey })
.rpc();
const account = await program.account.myAccount.fetch(myPda);
assert.equal(account.amount.toNumber(), 1000);
});
For more complex scenarios — bankrun (fast simulation without full validator) or solana-program-test in Rust.
Deployment to Devnet and Mainnet
# devnet
anchor deploy --provider.cluster devnet
# mainnet — via multisig (Squads Protocol) or program upgrade
solana program deploy target/deploy/my_program.so \
--program-id target/deploy/my_program-keypair.json \
--url mainnet-beta
For mainnet — mandatory program keypair in cold storage. Keypair loss = impossible to upgrade the program forever. We recommend Squads Protocol for multisig upgrade management.
After deployment — verify source code on Solana Explorer via solana-verify CLI from OtterSec:
solana-verify verify-from-repo \
--url https://api.mainnet-beta.solana.com \
--program-id YourProgramId \
https://github.com/yourorg/yourrepo
Environment setup time from scratch — 4-8 hours including first working test. CI/CD pipeline setup (GitHub Actions with Rust toolchain caching) + deployment script — another 1-2 days.







