Skip to content
0%

EVM vs SVM: a developer's guide

Uttam Singh

Written by Uttam Singh

Published on September 25, 20269 min read

EVM vs SVM: a developer's guide

Every blockchain runs on a virtual machine, the engine that executes programs and applies their state changes. Ethereum's engine is the EVM (Ethereum Virtual Machine), which also powers most of its Layer 2s. Solana's is the SVM (Solana Virtual Machine), built to run transactions in parallel. The core architectural difference is that the EVM stores a contract's code and state together, while the SVM keeps them in separate accounts. That difference shapes how programs store data, how transactions execute, and how fees respond to congestion.

This guide compares the two across account models, execution, fees, program design, and tooling, with short code examples, and closes with a framework for deciding where to build or port. If you prefer video, our SVM vs EVM builders guide covers the same comparison.

What are the EVM and SVM?

The EVM is a stack-based virtual machine that processes transactions one at a time, updating a single shared state tree. Its main advantage is compatibility. The same Solidity contract deploys unchanged to Ethereum, to its Layer 2s (Arbitrum, Base, Optimism, Unichain, World Chain, Ink), and to independent EVM chains (BNB Chain, Avalanche, Polygon, Monad, Berachain), and the surrounding tooling works everywhere the bytecode does. If the EVM is new to you, our Ethereum Virtual Machine explainer covers the fundamentals.

The SVM was designed around parallel execution. Programs compile to sBPF bytecode, a register-based format derived from eBPF (the same bytecode design the Linux kernel uses), and every transaction declares in advance which accounts it will read and write. This declaration allows Sealevel, Solana's parallel runtime, to run non-conflicting transactions simultaneously across CPU cores. Our Solana Virtual Machine explainer covers the execution pipeline in depth.

The table below summarizes the main differences.

Dimension
EVM
SVM

Account model

Code and storage bundled in contract accounts

Everything is an account; programs are stateless

Execution

Sequential within a block

Parallel across non-conflicting transactions

Virtual machine

Stack-based, 256-bit words

Register-based, eBPF-derived

Fee market

One global base fee plus tips

Base fee per signature plus priority fees scoped to contested accounts

Primary language

Solidity

Rust with Anchor

Tokens

One contract per token

Shared Token Program, one mint account per token

Upgrades

Immutable by default, proxies to upgrade

Upgradeable by default, revoke authority to freeze

How do the account models differ?

Ethereum has two account types: externally-owned accounts controlled by private keys, and contract accounts controlled by code. A contract account holds its own storage, a key-value store of 32-byte slots, alongside its bytecode. When you call balanceOf on an ERC-20 token, the contract reads your balance from a mapping in its own storage. Code and state share one address and cannot be separated.

Solana uses a single account model for everything. Every piece of state on Solana is an account with the same structure: a balance in lamports (Solana's smallest unit, like wei), a data field, an owner, and an executable flag. A program is an account whose data is sBPF bytecode and whose executable flag is set to true. The state a program manages lives in separate data accounts. The runtime enforces ownership directly, since only the program that owns an account can modify its data, which removes much of the access-control logic a Solidity contract implements itself. Our Solana data accounts vs. program accounts guide covers this split in detail.

Program derived addresses (PDAs) are usually the least familiar concept for EVM developers. Where a Solidity contract stores per-user data in a mapping, a Solana program derives a dedicated account address for each user from the program's ID and a set of seeds, typically the user's public key. The derivation is deterministic and produces an address off the Ed25519 curve, so no private key exists for it. Only the program can sign on its behalf. In practice, each entry in a Solidity mapping becomes its own account on Solana.

The two models also price storage differently. On Ethereum, you pay for storage once, in gas, when you write it. On Solana, every account must hold a refundable deposit proportional to its size, known as rent exemption. The deposit is returned when the account is closed, which gives developers a direct incentive to remove unused state.

How does parallel execution work on the SVM?

The EVM executes the transactions in a block sequentially. A transaction can read or write any storage slot, and those accesses are not known until it runs, so the EVM cannot safely execute two transactions at the same time.

Solana removes that uncertainty by requiring each transaction to list every account it will read and write before execution. The scheduler runs transactions that only read shared accounts in parallel and serializes transactions that write to the same account. A write lock allows one thread at a time. Transactions that need the same lock are queued and processed in order, and they do not fail because of the conflict.

This model affects program design. State that many users update at the same time should be split across multiple accounts, which is how SPL tokens (Solana's token standard) are structured. Two USDC transfers between unrelated wallets write to four different token accounts, so they can execute at the same time. On Ethereum, the same two transfers both update the storage of one ERC-20 contract and execute one after the other.

Parallel execution is also arriving in the EVM ecosystem. Monad runs a parallel-execution EVM L1 with full bytecode compatibility, and MegaETH applies similar techniques as an Ethereum L2. These chains detect conflicts at runtime rather than requiring transactions to declare their accounts, which preserves EVM compatibility while increasing throughput.

How do fees compare?

Ethereum uses one global fee market. Every transaction pays the same base fee, which the protocol adjusts each block and burns, plus an optional priority tip to the validator. A standard ETH transfer costs 21,000 gas, and blocks target 30 million gas with a 60 million gas limit. Because the base fee applies to the whole chain, demand from one application affects everyone. A popular NFT mint or airdrop claim raises the base fee for all users, including those of unrelated applications.

Solana uses a different fee structure. Every transaction pays a base fee of 5,000 lamports per signature, half of which is burned and half paid to the validator. Compute is metered in compute units (CU), with a default budget of 200,000 CU per instruction and a maximum of 1.4 million CU per transaction. Transactions can also include a prioritization fee, priced in micro-lamports per compute unit, to be scheduled ahead of others.

The key difference is the scope of fee competition. Because every transaction names the accounts it writes, priority-fee competition is concentrated among transactions that contend for the same accounts. The ecosystem refers to this behavior as local fee markets. The getRecentPrioritizationFees RPC method reflects this design by filtering fee samples by the writable accounts a transaction will lock. During a popular mint, fees rise for transactions that write to the mint's accounts, while unrelated transactions are largely unaffected.

This affects capacity planning. On Ethereum, activity from unrelated applications can raise your transaction costs, and application design cannot prevent it. On Solana, fee pressure comes mainly from contention on your own accounts, so distributing frequently written state across more accounts reduces it.

What changes in program design?

A Solidity contract is a single unit of code and storage, and it is immutable by design. Changing its logic after deployment requires a proxy pattern built on delegatecall, which routes calls to a replaceable implementation contract. A minimal Solidity counter looks like this:

solidity
Copied
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; contract Counter { uint64 public count; // state lives inside the contract itself function increment() external { count += 1; } }

The equivalent Solana program, written with Anchor (a widely used Solana program framework), stores no state itself. The counter value lives in a separate account that each call passes in explicitly:

rust
Copied
use anchor_lang::prelude::*; // Run anchor keys sync to set your program ID here and in Anchor.toml. declare_id!("REPLACE_WITH_YOUR_PROGRAM_ID"); #[program] mod counter { use super::*; pub fn increment(ctx: Context<Increment>) -> Result<()> { ctx.accounts.counter.count += 1; Ok(()) } } #[derive(Accounts)] pub struct Increment<'info> { #[account(mut)] pub counter: Account<'info, Counter>, // state account passed in explicitly } #[account] pub struct Counter { pub count: u64, }

A complete version would also include an initialize instruction to create and fund the counter account. Before the handler runs, Anchor checks each account against the Increment struct, which confirms the account has the expected type and owner. That check does not restrict who can call the instruction. As written, anyone can call increment, so a real program would add a signer requirement or a derived-address constraint to control who can update the counter.

The default upgrade behavior is reversed. Solana programs deployed with an upgrade authority are upgradeable natively, and revoking that authority makes the program immutable. Solana programs therefore do not need proxy contracts, which removes a category of code that EVM audits often focus on.

Tokens follow the same pattern. Each ERC-20 token is its own contract implementing a standard interface, so an application that supports many tokens depends on many independent codebases. On Solana, tokens are issued through a shared Token Program, with Token-2022 offering an extended version that supports optional features such as transfer fees. Each token is a mint account that records supply and decimals, and each holder's balance is stored in a token account. An application that integrates these programs can support any SPL token without per-token code.

Event handling is an area where the EVM has a clear advantage. EVM contracts emit indexed events that eth_getLogs and indexers consume natively. Solana has no native event system. Programs write log messages, and Anchor's event macros encode structured data into those logs, which can be truncated. As a result, production indexing on Solana typically relies on streaming infrastructure such as webhooks and Solana gRPC streaming.

What does the client stack look like?

The choice of VM also determines the language and tooling. EVM development uses Solidity and a mature toolchain (Foundry, Hardhat) with extensive support for testing, fuzzing, and deployment. Solana development uses Rust and Anchor, which has a steeper learning curve and a smaller, though growing, pool of auditors. Our web3 programming languages overview covers the language options in more detail.

The difference in data models is also visible in client code. On the EVM, reading state means calling a function on the contract, which returns data from its own storage. This example uses viem:

typescript
Copied
import { createPublicClient, http, parseAbi, formatUnits } from "viem"; import { mainnet } from "viem/chains"; const client = createPublicClient({ chain: mainnet, transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"), }); const balance = await client.readContract({ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC contract abi: parseAbi(["function balanceOf(address) view returns (uint256)"]), functionName: "balanceOf", args: ["0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503"], }); console.log(formatUnits(balance, 6));

On Solana, reading state means fetching the account that holds the data. A token balance is stored in a token account rather than in the Token Program, so the client reads that account directly. This example uses @solana/kit:

typescript
Copied
import { createSolanaRpc, address } from "@solana/kit"; const rpc = createSolanaRpc("https://solana-mainnet.g.alchemy.com/v2/YOUR_API_KEY"); // SOL balance: fetch the account's lamports by its address const { value: lamports } = await rpc .getBalance(address("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri")) .send(); // SPL balance: read the token account directly const { value: tokenBalance } = await rpc .getTokenAccountBalance(address("2ocS3orPq3jyszjsJ4NozKWyhdotr3csDjAizmkj65aH")) .send(); console.log(lamports, tokenBalance.uiAmountString);

This pattern applies across the client layer. An EVM client queries a contract, while a Solana client needs to know which account holds each piece of data, which makes account layout part of the application's design.

What breaks when you port an EVM app to Solana?

Moving an application from the EVM to Solana requires rewriting the onchain code, because the account and execution models are different. The main changes are:

  • msg.sender becomes signer accounts. Authorization on Solana comes from accounts marked as signers on the transaction and checked by your program, plus PDAs that the program signs for when the program itself holds authority.
  • Mappings become PDAs. Each key in a Solidity mapping becomes a derived account that must be created and rent-funded before first use. Reading the data changes as well, since clients fetch accounts rather than query contract storage.
  • Contract storage becomes sized, rent-funded accounts. State must be allocated in advance with a known size, and the deposit is returned when the account is closed.
  • Proxy upgrade patterns are no longer needed. The program's upgrade authority replaces the proxy setup, and revoking that authority makes the program immutable.
  • Events become logs and streaming. Any system that consumed eth_getLogs must be rebuilt around log parsing, webhooks, or gRPC streams.
  • The client and test stack change. Client code moves from viem to @solana/kit, tests move from Foundry to Anchor's test framework, and CI needs a local validator.

Teams moving in the other direction, from the SVM to the EVM, typically gain tooling depth, native event indexing, and a larger auditor market, and give up parallel execution, sub-second confirmation, and per-account fee isolation.

In both directions, the team's learning curve is usually the largest cost. For EVM engineers moving to Solana, our Solana development roadmap is a good starting point.

How do you choose between the EVM and SVM?

You are building
Suggested starting point
Why

A high-throughput consumer app (payments, trading, mints)

SVM

Parallel execution and per-account fee isolation keep costs stable under your own load

A DeFi protocol that composes with existing liquidity

EVM

Established DeFi protocols, integrations, and auditors are concentrated in the EVM ecosystem

A team experienced in Solidity with latency-tolerant products

EVM, or a parallel EVM chain

Staying on the existing stack avoids a rewrite when the workload does not require SVM throughput

How does Alchemy support EVM and SVM development?

We support both ecosystems from a single platform. Our RPC endpoints cover Ethereum, the major L2s, and the wider EVM ecosystem. Our Solana infrastructure delivers archive calls up to 20x faster with 99.99% uptime, and gRPC streaming provides the real-time data feeds that Solana indexing depends on. If you are evaluating Solana infrastructure, our Solana RPC guide covers what to look for in a provider.

A free API key gives you endpoints for EVM chains and Solana from one dashboard, with no contract or minimum commitment, and no need to integrate a separate provider for each ecosystem.

Background gradient

Build blockchain magic

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.