Rust + Anchor + Quasar: the standard Solana program stack in 2026
Solana programs are Rust. Anchor handles boilerplate. Quasar is the in-test cluster harness. Here's the canonical workflow from cargo new to mainnet deploy.
devrels.xyz/a/76short linkNew Solana program authors invariably converge on the same stack within a week: Rust for the program, Anchor for the ergonomic layer, and a fast test harness for the integration tests that would otherwise be unbearable against solana-test-validator. The harness used to be Mocha + solana-test-validator; increasingly it's LiteSVM or Quasar.
This article is the opinionated path through the standard stack — cargo new through mainnet deploy.
The shape of a project
my-program/
├── Anchor.toml # programs, cluster, wallet, scripts
├── Cargo.toml # workspace
├── programs/
│ └── my-program/
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # entrypoint + #[program] module
│ ├── instructions/
│ │ ├── mod.rs
│ │ ├── initialize.rs
│ │ └── transfer.rs
│ ├── state/
│ │ ├── mod.rs
│ │ └── vault.rs
│ └── errors.rs
├── tests/
│ └── my-program.ts # Mocha/Anchor TS tests
├── target/
│ ├── deploy/
│ │ ├── my_program.so # compiled BPF binary
│ │ └── my_program-keypair.json
│ └── idl/
│ └── my_program.json # generated IDLThe minimum Anchor program
use anchor_lang::prelude::*;
declare_id!("My111111111111111111111111111111111111111");
#[program]
pub mod my_program {
use super::*;
pub fn initialize(ctx: Context<Initialize>, name: String) -> Result<()> {
let vault = &mut ctx.accounts.vault;
vault.owner = ctx.accounts.payer.key();
vault.name = name;
vault.balance = 0;
Ok(())
}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
ctx.accounts.vault.balance = ctx
.accounts.vault.balance
.checked_add(amount)
.ok_or(MyError::Overflow)?;
Ok(())
}
}
#[derive(Accounts)]
#[instruction(name: String)]
pub struct Initialize<'info> {
#[account(init, payer = payer, space = 8 + Vault::INIT_SPACE,
seeds = [b"vault", payer.key().as_ref(), name.as_bytes()], bump)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, has_one = owner)]
pub vault: Account<'info, Vault>,
pub owner: Signer<'info>,
}
#[account]
#[derive(InitSpace)]
pub struct Vault {
pub owner: Pubkey,
#[max_len(32)]
pub name: String,
pub balance: u64,
}
#[error_code]
pub enum MyError {
#[msg("arithmetic overflow")]
Overflow,
}Anchor generates: the discriminator-based dispatcher, account validation (has_one, seeds, init rent payment), serialization, the IDL JSON, and the TypeScript client.
Building
anchor build
# Compiles programs/* to target/deploy/*.so + emits target/idl/*.json
anchor idl init -f target/idl/my_program.json <program_id>
# (Optional) writes the IDL to the on-chain IDL account so explorers can decode txs
anchor test
# Spins up solana-test-validator, deploys the program, runs tests/*.ts against itTests — the slow vs fast options
Default (Anchor): Mocha + solana-test-validator. Each anchor test takes ~10-30s to spin up the validator. Fine for a couple of tests, painful at 100+.
Fast (LiteSVM): in-process SVM, no validator. Same instruction dispatch, microsecond-fast. The default for unit and integration tests in 2026:
import { LiteSVM } from "litesvm"
import { PublicKey } from "@solana/web3.js"
const svm = new LiteSVM()
svm.addProgramFromFile(programId, "target/deploy/my_program.so")
svm.airdrop(payer.publicKey, 1_000_000_000n)
const ix = /* build your instruction */
const result = svm.sendTransaction(new Transaction().add(ix).sign(payer))
expect(result.err).toBeNull()
const vault = svm.getAccount(vaultPda)
// assertions on vault.data ...Mainnet-realistic (Surfpool): when you need real Mainnet state in the test (real USDC mint, real oracle accounts), use Surfpool with a fork. Slower than LiteSVM, far more realistic than vanilla solana-test-validator. See the Surfpool article.
Deploying to devnet → mainnet
# Switch CLI to devnet, deploy
solana config set --url https://api.devnet.solana.com
anchor deploy --provider.cluster devnet
# Output: program deployed at <program_id>
# Run your tests against the devnet deploy
anchor test --skip-deploy --provider.cluster devnet
# Once happy, switch to mainnet
solana config set --url https://api.mainnet-beta.solana.com
# Pre-fund the deploy wallet (~3 SOL for a moderate program)
solana airdrop 3 # only works on devnet; transfer SOL in for mainnet
anchor deploy --provider.cluster mainnet
# Or for explicit upgrade authority:
solana program deploy target/deploy/my_program.so \
--program-id target/deploy/my_program-keypair.json \
--upgrade-authority <your-multisig-or-key>Upgrade authority — set it carefully
First-time deploys default to making the deploy wallet the upgrade authority. Production programs should hand this off immediately:
# Transfer upgrade authority to a Squads multisig
solana program set-upgrade-authority <program_id> \
--new-upgrade-authority <squads_vault_pda> \
--skip-new-upgrade-authority-signer-check
# Or freeze the program (irrevocable!)
solana program set-upgrade-authority <program_id> --finalSee the Squads article for the recommended pattern.
Where Quasar fits
quasar in this stack name historically refers to rapid in-memory cluster harnesses for testing — the lineage runs through bankrun → LiteSVM → newer derivatives. The constant is: skip solana-test-validator for anything past basic smoke tests; use an in-process SVM for speed.
The opinionated stack, summarised
Language: Rust (stable channel, edition 2021)
Framework: Anchor 0.31+ (or Pinocchio for hot paths)
Local tests: LiteSVM for fast, Surfpool for Mainnet-realistic
Devnet tests: anchor test --provider.cluster devnet
TS client: codama-generated against @solana/kit
Frontend: gill (Next.js / React) or kit-squared (SvelteKit)
Deploy auth: Squads V4 multisig
CI: GitHub Actions → cargo test + anchor test (LiteSVM)References
Rust + Anchor + a fast SVM harness is the path 90% of Solana program authors land on. Layer in Pinocchio for hot paths, Squads for upgrade authority, and the stack scales to production.
Keep reading
An audit report is worthless if you can't confirm the deployed bytecode is what was audited. Solana verified builds fix that: a Docker-pinned toolchain produces a deterministic .so, its hash is compared to the on-chain program data, and the result is written to a PDA anyone can read. Solana Explorer shows a verified badge. Here's the full workflow.
Ephemeral Rollups sound exotic until you see the loop: it's one Anchor program, two RPC endpoints. You delegate a PDA to an ER validator, fire cheap 10ms transactions against it, then commit state back to Solana and undelegate. MagicBlock's examples repo is the cleanest way to learn it — here's the lifecycle in real code and a map of where to start.
Anchor optimises for developer experience. Pinocchio optimises for compute units. Steel sits in the middle. Bundle size, CU cost, and ergonomics — compared.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.
