Skip to main content

Overview

LiteSVM is a fast and lightweight library for testing Solana programs. It works by creating an in-process Solana VM optimized for program developers, making it much faster to run and compile than alternatives like solana-program-test and solana-test-validator. LiteSVM is available in:
  • Rust - Full-featured testing in Rust
  • TypeScript/JavaScript - Client-side testing with full SVM access
  • Python - Testing via the solders library

Key Features

  • Blazingly Fast - No validator startup time, tests run in milliseconds
  • Lightweight - Minimal resource usage, compiles quickly
  • Multi-Language - Use Rust, TypeScript, or Python
  • Time Travel - Manipulate clock and slots for testing time-dependent logic
  • Arbitrary Accounts - Write any account data, even impossible states
  • Real SVM - Tests run against actual Solana VM, not a mock

When to Use LiteSVM

LiteSVM is ideal for:
  • Unit Testing - Test individual instructions in isolation
  • Fast Iteration - Rapid test feedback during development
  • CI/CD Pipelines - Quick test execution in automated builds
  • Account Manipulation - Testing edge cases with custom account states
  • Time-Dependent Logic - Programs that use the Clock sysvar
Use solana-test-validator when you need full RPC support or want to test against real validator behavior.

Installation

cargo add litesvm --dev

Quick Start

Here’s a simple transfer example to get you started:
use litesvm::LiteSVM;
use solana_sdk::{
    signature::{Keypair, Signer},
    transaction::Transaction,
    system_instruction::transfer,
    message::Message,
};

#[test]
fn test_transfer() {
    let mut svm = LiteSVM::new();
    let from = Keypair::new();
    let to = Keypair::new();
    
    // Airdrop SOL to sender
    svm.airdrop(&from.pubkey(), 10_000_000).unwrap();
    
    // Create transfer instruction
    let ix = transfer(&from.pubkey(), &to.pubkey(), 1_000_000);
    let tx = Transaction::new(
        &[&from],
        Message::new(&[ix], Some(&from.pubkey())),
        svm.latest_blockhash(),
    );
    
    // Send transaction
    svm.send_transaction(tx).unwrap();
    
    // Verify balances
    assert_eq!(svm.get_balance(&to.pubkey()), 1_000_000);
}

Testing Anchor Programs

To test an Anchor program with LiteSVM, you need to load the compiled program binary:
use litesvm::LiteSVM;
use solana_sdk::{
    signature::Keypair,
    signer::Signer,
    instruction::{Instruction, AccountMeta},
    transaction::Transaction,
    message::Message,
};

#[test]
fn test_anchor_program() {
    let mut svm = LiteSVM::new();
    let program_id = /* your program ID */;
    
    // Load program from compiled binary
    let program_data = include_bytes!("../../target/deploy/my_program.so");
    svm.add_program(program_id, program_data);
    
    // Set up accounts
    let user = Keypair::new();
    let my_account = Keypair::new();
    svm.airdrop(&user.pubkey(), 10_000_000).unwrap();
    
    // Create instruction (using Anchor IDL)
    let ix = Instruction {
        program_id,
        accounts: vec![
            AccountMeta::new(my_account.pubkey(), true),
            AccountMeta::new(user.pubkey(), true),
            AccountMeta::new_readonly(solana_sdk::system_program::ID, false),
        ],
        data: vec![/* instruction data */],
    };
    
    // Send transaction
    let tx = Transaction::new(
        &[&user, &my_account],
        Message::new(&[ix], Some(&user.pubkey())),
        svm.latest_blockhash(),
    );
    
    let result = svm.send_transaction(tx).unwrap();
    assert!(result.result.is_ok());
}

Time Travel

LiteSVM allows you to manipulate the Clock sysvar to test time-dependent logic:
use litesvm::LiteSVM;
use solana_sdk::clock::Clock;

#[test]
fn test_time_travel() {
    let mut svm = LiteSVM::new();
    
    // Get current clock
    let mut clock = svm.get_sysvar::<Clock>();
    println!("Current time: {}", clock.unix_timestamp);
    
    // Advance time by 1 hour
    clock.unix_timestamp += 3600;
    svm.set_sysvar::<Clock>(&clock);
    
    // Verify new time
    let new_clock = svm.get_sysvar::<Clock>();
    assert_eq!(new_clock.unix_timestamp, clock.unix_timestamp);
}
You can also jump to a specific slot:
svm.warp_to_slot(1000);

Arbitrary Account States

LiteSVM lets you write any account data, even states that would be impossible to achieve normally. This is useful for testing edge cases:
use litesvm::LiteSVM;
use solana_sdk::{
    account::Account,
    pubkey::Pubkey,
};
use spl_token::state::{Account as TokenAccount, AccountState};

#[test]
fn test_arbitrary_token_balance() {
    let mut svm = LiteSVM::new();
    let owner = Pubkey::new_unique();
    let token_account = Pubkey::new_unique();
    
    // Create token account with arbitrary balance
    let account_data = TokenAccount {
        mint: Pubkey::new_unique(),
        owner,
        amount: 1_000_000_000_000, // 1 trillion tokens!
        delegate: None,
        state: AccountState::Initialized,
        is_native: None,
        delegated_amount: 0,
        close_authority: None,
    };
    
    let mut data = vec![0u8; TokenAccount::LEN];
    TokenAccount::pack(account_data, &mut data).unwrap();
    
    svm.set_account(
        token_account,
        Account {
            lamports: 1_000_000,
            data,
            owner: spl_token::ID,
            executable: false,
            rent_epoch: 0,
        },
    ).unwrap();
    
    // Now test with this account
    let acc = svm.get_account(&token_account).unwrap();
    let token_acc = TokenAccount::unpack(&acc.data).unwrap();
    assert_eq!(token_acc.amount, 1_000_000_000_000);
}

Advanced Features

Compute Budget Control

let mut svm = LiteSVM::new()
    .with_compute_budget(1_000_000); // Set max compute units

Disable Signature Verification

let mut svm = LiteSVM::new()
    .with_sigverify(false); // Skip signature checks (faster tests)

Transaction History

let tx_result = svm.send_transaction(tx).unwrap();
let signature = tx_result.signature;

// Later, retrieve transaction
let stored_tx = svm.get_transaction(signature);

Performance Comparison

FrameworkStartup TimeTest SpeedResource Usage
LiteSVM~0msFastestMinimal
solana-program-test~50msFastLow
solana-test-validator~5000msSlowHigh

Best Practices

  1. Use LiteSVM for unit tests - Test individual instructions quickly
  2. Use test-validator for integration - Test full workflows and RPC interactions
  3. Mock account states - Use arbitrary accounts to test edge cases
  4. Time travel for scheduling - Test time-locked features without waiting
  5. Parallel tests - LiteSVM tests can run in parallel safely

Limitations

  • No RPC methods - LiteSVM doesn’t expose RPC endpoints
  • Simplified validator - Doesn’t simulate all validator behaviors
  • No cross-program invocation limits - May behave differently than production
For testing that requires full validator fidelity, use solana-test-validator.

Next Steps

  • Learn about [Mollusktesting/mollusk) for even lighter Rust testing
  • Explore [Testing Overviewtesting/overview) for testing strategies
  • Check out the LiteSVM GitHub for more examples

Build docs developers (and LLMs) love