
If you maintain an upgradeable Solana program, please check that you can compile and deploy it as sBPF v3. Preferably before someone finds a bug you need to fix immediately.
Solana is preparing to stop accepting deployments of programs compiled for older sBPF versions. Once SIMD-0500 activates, new deployments and upgrades must target at least v3. It also blocks finalizing older programs, meaning permanently removing their upgrade authority.
Existing v0, v1, and v2 programs will keep running. You can still upgrade an old program to v3 after activation. The version of the replacement binary is what matters.
So you can postpone the migration. I just think doing it during an incident would be a particularly annoying way to discover that a dependency needs updating or your program no longer compiles.
During normal development, you have time to figure that out. During an incident, you want to make the smallest possible fix, test it, and deploy it. Adding a compiler and dependency migration to that process gives you more changes to review precisely when you have less time to review them.
The Foundation expects the restriction on older deployments to activate on mainnet in November 2026, with Agave 4.4. As of September 22, v3 itself is already enabled on mainnet, devnet, and testnet. We checked the feature accounts: the separate restriction is inactive on all three. You can migrate now.
Anza's tentative v4.4 schedule, updated September 21, gives these milestones:
| Target date (2026) | Planned milestone |
|---|---|
| September 28 | Recommend v4.4 adoption on testnet |
| October 5 | Upgrade devnet to v4.4; resume testnet feature activations |
| October 7 | Resume devnet feature activations |
| November 2 | Recommend v4.4 for general mainnet adoption |
| November 9 | Resume mainnet feature activations |
These dates describe the release rollout. November 9 is not a confirmed SIMD-0500 activation date. The Foundation's announcement gives a month, and the feature-gate tracker does not yet list a specific activation epoch for SIMD-0500. Both the release schedule and individual feature activations can move.
I would aim to finish the rebuild, testing, and production upgrade during October. That is our planning recommendation, not an official deadline. Check the linked rollout page and tracker before scheduling your release, particularly if you rely on devnet or testnet, where feature activations are planned to resume earlier.
sBPF is the bytecode your Solana program compiles to. Its version determines how the runtime reads and executes the compiled .so file. This is separate from your Anchor version or the validator version. It is also separate from loader-v3, which manages program deployments and upgrades. There are unfortunately several unrelated version numbers involved.
The main reason for v3 is to simplify program loading and bring Solana closer to the instruction set supported by upstream eBPF tools. Supporting several formats means keeping their different loading and execution rules around. Requiring new deployments to use v3 lets the network work toward retiring the older formats over time.
One change is static syscalls. When your program calls a runtime function, older formats require the loader to resolve the reference and patch the executable. With v3, the build tools put the syscall identifier directly into the binary, so that work is already done when the validator loads it.
v3 also requires a stricter ELF layout. ELF is the file format of your .so. Allowing fewer layouts makes the loader simpler and reduces its attack surface. The instruction-set changes similarly reduce the amount of Solana-specific behavior compiler maintainers have to support.
One slightly surprising detail: v3 removes some features from v2.
| sBPF v2 | sBPF v3 | |
|---|---|---|
| Syscalls | Resolved through relocations when loading | Static identifiers emitted during the build |
| ELF layout | Legacy loading rules | Strict headers and segment layout, without runtime relocations |
| Arithmetic | Custom PQR instructions for multiplication, division, and remainders | Removes PQR and returns to eBPF-compatible encodings |
| Stack | Dynamic stack frames | Fixed frames, normally 4,096 bytes per function, without gaps |
| Branches and indirect calls | No JMP32; callx uses the source-register field |
Supports 32-bit conditional branches; callx uses the destination-register field |
You can see these differences in the sBPF version switches and stack-frame handling.
For ordinary Rust code, the compiler handles the instruction changes. If you maintain assembly, custom syscall bindings, linker scripts, or other low-level code, look more closely. The read-only data region moves too. Changing the version number in an old ELF header will not convert any of this.
And don't assume v3 makes your program cheaper to execute. Less work during loading does not guarantee lower CU consumption for your instructions. Measure it. Our cost of security analysis breaks down what common operations and checks actually cost in compute units.
Anza recommends platform-tools v1.56+, cargo-build-sbf v4.2.0+, and solana-define-syscall v3.0.0+. Check your framework and dependencies as well, then pin the versions you tested. Some old tools accepted --arch v3 while producing an outdated format, so the flag alone is insufficient.
With a compatible toolchain:
cargo build-sbf --arch v3 --tools-version v1.56
readelf -h target/deploy/your_program.so
Use your program's filename. The header should show Flags: 0x3. Make sure CI and any Anchor or verifiable-build wrapper use the same target and toolchain. The build-tool documentation explains the options.
There is already a documented reason to be careful here. Anza describes older syscall bindings leaving unresolved calls in a v3 binary. The binary can pass deployment verification, but invoking the affected code then fails with CallDepthExceeded. cargo-build-sbf v4.2.0 adds a linker check to catch unresolved symbols during compilation. If that check fails, fix the binding or dependency rather than disabling it.
Also read the build logs. Anza notes that a stack-overflow diagnostic can appear there without causing the build to fail. A successful exit code is not a reason to ignore it.
Start with the source of your current production release. Keep unrelated changes out of the migration, and review whatever dependency or framework updates are required. Save the source commit, lockfile, tool versions, build flags, and binary hash so you can reproduce the build later.
Then run the compiled v3 program in the Solana Virtual Machine. Host-side Rust tests don't execute the binary you are deploying. A current version of Mollusk, LiteSVM, or a local validator can do that. If you don't already have a suite that exercises those paths, here is how to build one that catches real bugs.
Use existing account state, including the large and awkward cases. Test CPIs, error paths, withdrawals, and any liquidation or recovery instructions your program has. Compare the resulting state and return values with the old build, check account-layout and instruction compatibility, and measure compute consumption again.
You should also test an upgrade through the loader with the older-format restriction enabled. Some test setups put a binary straight into the program cache. That is useful for testing execution, but skips the deployment checks. Upgrade a program with populated accounts, then run it again.
Keep the same program ID. The normal upgrade mechanism replaces the code without replacing the Program account. Moving to v3 does not require a new program address.
There is one more thing I would check: what does your rollback procedure deploy?
If the answer is an archived v2 .so, that will also be rejected after activation. The loader checks the incoming binary. Calling it a rollback does not give it an exception.
Keep a tested v3 build of a known-good release and the inputs needed to rebuild it. Test it against the state your newer release leaves behind. Replacing the code will not undo transactions or reverse an account migration. If going backward is unsafe, prepare and test the forward fix you would need instead.
Once this works, deploy the reviewed v3 build through your usual release process. Check the deployed bytes against the approved artifact you built and reviewed, not just an on-chain verification label, which can be spoofed. Monitor the important instructions afterward. Use the exercise to confirm that the people handling an incident can access the build environment, signers, fee funds, and RPC infrastructure, while keeping your existing authority controls.
Our recommendation is to do this now: rebuild, test, and redeploy while you have time to fix whatever breaks. Finding a compiler problem is annoying enough without also watching an incident unfold.