---
title: Quick Start
description:
  Learn how to use the litesvm-loader crate for testing upgradeable program
  deployment
---

<div className="flex items-center gap-3 mb-6">
  <a
    href="https://crates.io/crates/litesvm-loader"
    target="_blank"
    rel="noopener noreferrer"
    className="inline-flex items-center gap-2 px-3 py-1.5 bg-fd-muted/50 hover:bg-fd-muted rounded-lg text-sm font-medium transition-colors border border-fd-border/50"
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
      className="w-4 h-4"
      fill="currentColor"
    >
      <path d="M239.1 6.3l-208 78c-18.7 7-31.1 25-31.1 45v225.1c0 18.2 10.3 34.8 26.5 42.9l208 104c13.5 6.8 29.4 6.8 42.9 0l208-104c16.3-8.1 26.5-24.8 26.5-42.9V129.3c0-20-12.4-37.9-31.1-44.9l-208-78C262 2.2 250 2.2 239.1 6.3zM256 68.4l192 72v1.1l-192 78-192-78v-1.1l192-72zm32 356V275.5l160-65v133.9l-160 80z" />
    </svg>
    View <code>litesvm-loader</code> on crates.io
  </a>
</div>

## Installation

Make sure you have all the needed dependencies:

```bash
cargo add --dev litesvm litesvm-loader solana-keypair solana-signer
```

If your test invokes the deployed program directly, also add the Solana
instruction and transaction crates used by your test:

```bash
cargo add --dev solana-instruction solana-message solana-transaction
```

## What is litesvm-loader?

The `litesvm-loader` crate provides helpers for deploying programs through the
BPF upgradeable loader inside LiteSVM. Use it when your test needs loader-owned
program accounts, program data accounts, or upgrade authority behavior instead
of directly inserting a program with `svm.add_program(...)`.

<Steps>
<Step>
**Upgradeable Deployment**
- Creates the loader buffer account
- Writes program bytes in chunks
- Deploys the final program account with the BPF upgradeable loader
- Uses the provided program keypair as the program ID
</Step>

<Step>
  **Upgrade Authority Management** - Changes the upgrade authority for an
  already deployed program - Supports assigning a new authority - Supports
  passing `None` to make the program immutable
</Step>

<Step>
**Real Loader State**
- Exercises the same loader account model your program sees on-chain
- Lets tests inspect program and program data accounts
- Helps catch mistakes hidden by direct program insertion
</Step>
</Steps>

<Callout type="info">
  For most tests, `svm.add_program(program_id, program_bytes)` is still the
  fastest and simplest way to load a program. Use `litesvm-loader` when the
  loader account layout or upgrade authority is part of what you need to test.
</Callout>

## Quick Example

Here's a complete example that deploys a program through the upgradeable loader
and then rotates its authority:

```rust
use litesvm::LiteSVM;
use litesvm_loader::{deploy_upgradeable_program, set_upgrade_authority};
use solana_keypair::Keypair;
use solana_signer::Signer;

#[test]
fn test_upgradeable_deployment() {
    let mut svm = LiteSVM::new();

    let payer = Keypair::new();
    svm.airdrop(&payer.pubkey(), 10_000_000_000).unwrap();

    // Use the keypair that should own the program ID.
    // For Anchor programs, this is usually target/deploy/<program>-keypair.json.
    let program = Keypair::new();
    let program_bytes = include_bytes!("../target/deploy/my_program.so");

    deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();

    let program_account = svm.get_account(&program.pubkey()).unwrap();
    assert!(program_account.executable);

    let new_authority = Keypair::new();
    set_upgrade_authority(
        &mut svm,
        &payer,
        &program.pubkey(),
        &payer,
        Some(&new_authority.pubkey()),
    )
    .unwrap();
}
```

## Choosing the Program Keypair

`deploy_upgradeable_program` uses the `program_kp` argument as the program
address. If your program declares a fixed ID, load the generated deploy keypair
instead of creating a random keypair:

```rust
use solana_keypair::read_keypair_file;

let program = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();
deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();
```

## Invoking the Deployed Program

After deployment, call the program the same way you would call any
LiteSVM-loaded program. Build an instruction for your program, sign the
transaction, and send it through the same `LiteSVM` instance:

```rust
use solana_instruction::Instruction;
use solana_message::Message;
use solana_transaction::Transaction;

let instruction = Instruction::new_with_bytes(
    program.pubkey(),
    &[],  // instruction data for your program
    vec![], // account metas for your program
);

let message = Message::new(&[instruction], Some(&payer.pubkey()));
let tx = Transaction::new(&[&payer], message, svm.latest_blockhash());

svm.send_transaction(tx).unwrap();
```

## Key Components

### deploy_upgradeable_program

| Argument        | Description                                                   |
| --------------- | ------------------------------------------------------------- |
| `svm`           | Mutable `LiteSVM` instance that receives the deployed program |
| `payer_kp`      | Fee payer and initial upgrade authority                       |
| `program_kp`    | Keypair whose public key becomes the program ID               |
| `program_bytes` | Compiled SBF program bytes, usually from `target/deploy/*.so` |

`deploy_upgradeable_program` creates a loader buffer, writes the program bytes
in 512-byte chunks, and deploys the program with room for future upgrades.

### set_upgrade_authority

| Argument                    | Description                                                    |
| --------------------------- | -------------------------------------------------------------- |
| `svm`                       | Mutable `LiteSVM` instance containing the deployed program     |
| `from_keypair`              | Fee payer and signing authority for the transaction            |
| `program_address`           | Program ID whose authority should change                       |
| `current_authority_keypair` | Current upgrade authority keypair                              |
| `new_authority_address`     | New authority address, or `None` to make the program immutable |

<Callout type="warn">
  In the current helper implementation, the generated transaction is signed by
  `from_keypair`. Pass the current authority as `from_keypair`, or keep the
  payer and current authority the same, when changing upgrade authority.
</Callout>

## Common Workflows

### Deploy with the declared program ID

```rust
use solana_keypair::read_keypair_file;

let program = read_keypair_file("target/deploy/my_program-keypair.json").unwrap();
let program_bytes = include_bytes!("../target/deploy/my_program.so");

deploy_upgradeable_program(&mut svm, &payer, &program, program_bytes).unwrap();
```

### Make a program immutable

```rust
set_upgrade_authority(
    &mut svm,
    &payer,
    &program.pubkey(),
    &payer,
    None,
)
.unwrap();
```

## Troubleshooting

### Common Errors

| Error                                                                 | Cause                                                                          | Solution                                                                                              |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
| `ProgramAccountNotFound` or instruction failures against the wrong ID | The deployment used a random `Keypair` while the program expects a declared ID | Read `target/deploy/<program>-keypair.json` and pass that keypair to `deploy_upgradeable_program`     |
| `InsufficientFunds`                                                   | The payer does not have enough lamports for loader buffer and program accounts | Airdrop more lamports before deployment                                                               |
| `MissingRequiredSignature` when changing authority                    | The current authority did not sign the transaction                             | Pass the current authority as `from_keypair`, or keep payer and current authority as the same keypair |
| Program deployment is slower than expected                            | Loader deployment writes bytes through real loader instructions                | Use `svm.add_program(...)` when you do not need loader state or upgrade authority behavior            |
