Loading Programs & Fixtures
Preload programs and deterministic account fixtures so every test run starts from the same on-chain state.
Recipe
Quick-reference recipe card - copy-paste ready.
solana-test-validator --reset \
--bpf-program <PROGRAM_ID> target/deploy/my_program.so \
--account <PUBKEY> fixture.json
anchor testWhen to reach for this:
- CI pipelines that must not depend on devnet uptime.
- Tests requiring known token balances or config accounts.
- Loading third-party
.sobinaries at fixed IDs. - Sharing fixture files across team members.
Working Example
# 1. Export a fixture account once from devnet/mainnet
solana account <CONFIG_PUBKEY> --output json-compact > config-fixture.json
# 2. Start validator with program + fixture
PROGRAM_ID=$(solana-keygen pubkey target/deploy/my_program-keypair.json)
solana-test-validator --reset \
--bpf-program "$PROGRAM_ID" target/deploy/my_program.so \
--account <CONFIG_PUBKEY> config-fixture.json
# 3. Run tests against known state
solana config set --url http://127.0.0.1:8899
anchor test --skip-local-validatorWhat this demonstrates:
--bpf-programloads your bytecode at genesis.--accountinjects lamports/owner/data from exported JSON.- Tests assert against stable config rather than random devnet state.
Deep Dive
How It Works
- Fixture JSON encodes account fields the validator applies at startup.
- Programs can be local builds or downloaded
.sofromsolana program dump. - Anchor tests can start validator with custom flags via
Anchor.toml[test.validator]section. - LiteSVM 0.6.x offers code-level fixtures for Rust unit tests without RPC.
Fixture Sources
| Source | Command | Use case |
|---|---|---|
| RPC export | solana account --output json | Realistic configs |
| Hand-written JSON | editor | Minimal synthetic state |
| Test setup txs | before hooks | Dynamic but slower |
| LiteSVM set_account | Rust API | Fast unit tests |
bash Notes
# Anchor.toml example
# [test.validator]
# url = "https://api.mainnet-beta.solana.com"
# clone = ["<MINT>", "<ORACLE>"]Gotchas
- Non-deterministic before hooks - tests flake when setup order changes. Fix: prefer static fixtures for CI gates.
- Wrong owner in fixture JSON - account rejected at load. Fix: copy exact owner from source
solana account. - Fixture drift - exported devnet account changes externally. Fix: version fixture files in git with comments on origin slot.
- Oversized fixtures - slow git and validator boot. Fix: trim data or generate programmatically in tests.
- Program ID mismatch in bpf-program - clients call wrong address. Fix: sync
declare_id!and keypair pubkey.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
--clone from mainnet | Live layout needed | Tiny config-only tests |
| On-chain setup instructions | Testing init flows | Repeated CI cost |
| LiteSVM | Pure Rust program logic | End-to-end RPC clients |
| devnet shared deploy | Team manual QA | Automated PR checks |
FAQs
Where do fixture JSON files live?
Common pattern: tests/fixtures/ committed to git with documented origin.
Can Anchor.toml configure clones?
Yes under [test.validator] with clone array and url for source cluster.
How do I load multiple programs?
Repeat --bpf-program <ID> <SO> flags on one validator command line.
Do fixtures include rent-exempt balance?
Exported JSON includes lamports - ensure enough for rent when injecting manually.
Can I update fixture mid-test?
Transactions can mutate state after boot - fixtures are only initial conditions.
How do I share fixtures securely?
Do not commit private user data - sanitize pubkeys and balances in shared fixtures.
Does this work with Surfpool?
Surfpool fork reduces need for manual fixtures - still useful for custom config overlays.
How big can fixture data be?
Match account size limits - large accounts slow startup proportionally.
Can I load upgradeable programs?
Load .so at program ID; upgrade authority behaves per loader rules on localnet.
How do I regenerate fixtures?
Re-run solana account --output json against known good cluster state and bump file version in commit message.
Related
- solana-test-validator - startup flags
- Cloning Mainnet Accounts - live snapshots
- LiteSVM - in-memory fixtures
- Testing Against a Validator - integration tests
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.