LiteSVM
LiteSVM 0.6.x runs an in-process Solana VM for sub-second program tests without solana-test-validator. Use it for unit tests, security negative cases, and tight Rust feedback loops.
Search across all documentation pages
LiteSVM 0.6.x runs an in-process Solana VM for sub-second program tests without solana-test-validator. Use it for unit tests, security negative cases, and tight Rust feedback loops.
Quick-reference recipe card - copy-paste ready.
use litesvm::LiteSVM;
use solana_sdk::{
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
signature::Keypair,
signer::Signer,
transaction::Transaction,
};
let mut svm = LiteSVM::new();
let payer = Keypair::new();
svm.airdrop(&payer.pubkey(), 10_000_000_000).unwrap();
svm.add_program(program_id, include_bytes!("../target/deploy/my_program.so"));When to reach for this:
#[test].anchor test.use litesvm::LiteSVM;
use solana_sdk::{
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
signature::Keypair,
signer::Signer,
system_program,
transaction::Transaction,
};
#[test]
fn withdraw_requires_signer() {
let program_id = Pubkey::new_unique();
let mut svm = LiteSVM::new();
svm.add_program(program_id, include_bytes!("../target/deploy/my_program.so"));
let payer = Keypair::new();
svm.airdrop(&payer.pubkey(), 2_000_000_000).unwrap();
let vault = Pubkey::new_unique();
let ix = Instruction {
program_id,
accounts: vec![
AccountMeta::new(vault, false),
AccountMeta::new_readonly(payer.pubkey(), false), // missing signer
],
data: vec![1, 0, 0, 0], // withdraw discriminator stub
};
let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&payer.pubkey()),
&[&payer],
svm.latest_blockhash(),
);
let result = svm.send_transaction(tx);
assert!(result.is_err());
}What this demonstrates:
.so directly into LiteSVM.| Tool | Speed | Fidelity | Language |
|---|---|---|---|
| LiteSVM 0.6.x | Fastest | High for ix logic | Rust |
| Mollusk | Fast | Instruction-focused | Rust |
| Bankrun | Fast | TS ergonomics | TypeScript |
| test-validator | Slow | Full RPC | Any |
// Advance clock for staleness tests
svm.set_sysvar(&solana_sdk::clock::Clock {
unix_timestamp: 1_700_000_000,
..Default::default()
});anchor build in CI before cargo test.svm.add_program for dependencies.svm.expire_blockhash() or refresh. Fix: Fetch latest_blockhash() per tx.Cargo.toml features as release build.| Alternative | Use When | Don't Use When |
|---|---|---|
| Mollusk | Instruction-level Rust only | You want full tx simulation ergonomics |
| Bankrun | TypeScript team | Pure Rust workflow |
| anchor test | Full integration | Inner-loop speed |
Pin LiteSVM 0.6.x per manifest; verify release notes for syscall compatibility.
Yes - load callee programs (Token, your vault) and supply correct account graph.
svm.airdrop for SOL; manually set token account data for SPL balances.
Use raw .so + instruction data, or community helpers to build Anchor discriminators.
cargo test after anchor build - no validator service required for LiteSVM layer.
Include correct PDA account with is_signer: false; program invokes signed CPI internally.
Failed txs return logs in error - assert log substrings for custom msg! debugging.
Each test should own LiteSVM::new() - avoid shared mutable svm across threads.
Use same program IDs as target cluster when testing CPI allowlists.
When depending on RPC methods, ALTs, or multi-tx landing behavior.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 16, 2026