---
title: "EVM vs SVM: a developer's guide"
description: "A developer comparison of the EVM and SVM covering account models, parallel execution, fees, program design, and migration, with code examples."
---

# EVM vs SVM: a developer's guide

<ImageBlock
  src="https://media.alchemy.com/overviews/evm-vs-svm-hero-20260924.png"
  alt="EVM vs SVM: a developer's guide"
  width={1920}
  height={900}
  priority
/>

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](https://www.youtube.com/watch?v=OsposMFk9Ro) 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](https://ethereum.org/en/developers/docs/evm/), 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](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm) covers the fundamentals.

The SVM was designed around parallel execution. Programs compile to [sBPF bytecode](https://solana.com/docs/core/programs), 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](https://solana.com/docs/references/terminology), to run non-conflicting transactions simultaneously across CPU cores. Our [Solana Virtual Machine explainer](https://www.alchemy.com/overviews/what-is-the-solana-virtual-machine) covers the execution pipeline in depth.

The table below summarizes the main differences.

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 240, title: "Dimension", dataType: "object" },
      { key: "2", width: 240, title: "EVM", dataType: "object" },
      { key: "3", width: 240, title: "SVM", dataType: "object" },
    ],
    data: [
      {
        "1": {
          title: "<p>Account model</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Code and storage bundled in contract accounts</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Everything is an account; programs are stateless</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title: "<p>Execution</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Sequential within a block</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Parallel across non-conflicting transactions</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": {
          title: "<p>Virtual machine</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Stack-based, 256-bit words</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Register-based, eBPF-derived</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
      {
        "1": {
          title: "<p>Fee market</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>One global base fee plus tips</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Base fee per signature plus priority fees scoped to contested accounts</p>",
          tooltip: "",
          icon: "",
        },
        id: 3,
      },
      {
        "1": {
          title: "<p>Primary language</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Solidity</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Rust with Anchor</p>",
          tooltip: "",
          icon: "",
        },
        id: 4,
      },
      {
        "1": {
          title: "<p>Tokens</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>One contract per token</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Shared Token Program, one mint account per token</p>",
          tooltip: "",
          icon: "",
        },
        id: 5,
      },
      {
        "1": {
          title: "<p>Upgrades</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>Immutable by default, proxies to upgrade</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title: "<p>Upgradeable by default, revoke authority to freeze</p>",
          tooltip: "",
          icon: "",
        },
        id: 6,
      },
    ],
  }}
/>

## How do the account models differ?

Ethereum has [two account types](https://ethereum.org/en/developers/docs/accounts/): 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](https://www.alchemy.com/overviews/solana-account-model) for everything. [Every piece of state on Solana is an account](https://solana.com/docs/core/accounts) 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](https://www.alchemy.com/overviews/solana-data-vs-program-accounts) 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](https://solana.com/docs/core/pda), 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](https://solana.com/docs/core/accounts), known as [rent exemption](https://www.alchemy.com/overviews/how-to-calculate-rent-for-solana-programs). 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](https://docs.anza.xyz/validator/runtime). 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](https://docs.monad.xyz/introduction/why-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](https://ethereum.org/en/developers/docs/gas/), 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](https://ethereum.org/en/developers/docs/blocks/). 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](https://solana.com/docs/core/fees), 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`](https://solana.com/docs/rpc/http/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](https://ethereum.org/en/developers/docs/smart-contracts/upgrading/). 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:

<CodeSnippet
  language="solidity"
  code={`// 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](https://www.alchemy.com/overviews/solana-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:

<CodeSnippet
  language="rust"
  code={`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](https://solana.com/docs/core/programs), 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](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) 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](https://solana.com/docs/tokens), 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](https://www.anchor-lang.com/docs/features/events). 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](https://www.alchemy.com/webhooks) and [Solana gRPC streaming](https://www.alchemy.com/solana-grpc).

## 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](https://www.alchemy.com/overviews/web3-programming-languages) 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:

<CodeSnippet
  language="typescript"
  code={`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`:

<CodeSnippet
  language="typescript"
  code={`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](https://solana.com/docs/core/cpi) 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](https://www.alchemy.com/overviews/learn-solana-development) is a good starting point.

## How do you choose between the EVM and SVM?

<EmbeddedTable
  table={{
    columns: [
      { key: "1", width: 240, title: "You are building", dataType: "object" },
      {
        key: "2",
        width: 240,
        title: "Suggested starting point",
        dataType: "object",
      },
      { key: "3", width: 240, title: "Why", dataType: "object" },
    ],
    data: [
      {
        "1": {
          title:
            "<p>A high-throughput consumer app (payments, trading, mints)</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>SVM</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Parallel execution and per-account fee isolation keep costs stable under your own load</p>",
          tooltip: "",
          icon: "",
        },
        id: 0,
      },
      {
        "1": {
          title: "<p>A DeFi protocol that composes with existing liquidity</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>EVM</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Established DeFi protocols, integrations, and auditors are concentrated in the EVM ecosystem</p>",
          tooltip: "",
          icon: "",
        },
        id: 1,
      },
      {
        "1": {
          title:
            "<p>A team experienced in Solidity with latency-tolerant products</p>",
          tooltip: "",
          icon: "",
        },
        "2": {
          title: "<p>EVM, or a parallel EVM chain</p>",
          tooltip: "",
          icon: "",
        },
        "3": {
          title:
            "<p>Staying on the existing stack avoids a rewrite when the workload does not require SVM throughput</p>",
          tooltip: "",
          icon: "",
        },
        id: 2,
      },
    ],
  }}
/>

<ExternalVideo
  url="https://www.youtube.com/watch?v=OsposMFk9Ro"
  provider="youtube"
  providerUid="OsposMFk9Ro"
/>

## How does Alchemy support EVM and SVM development?

We support both ecosystems from a single platform. Our [RPC endpoints](https://www.alchemy.com/rpc-api) cover Ethereum, the major L2s, and the wider EVM ecosystem. Our [Solana infrastructure](https://www.alchemy.com/blog/solana-infrastructure) delivers archive calls up to 20x faster with 99.99% uptime, and [gRPC streaming](https://www.alchemy.com/solana-grpc) provides the real-time data feeds that Solana indexing depends on. If you are evaluating Solana infrastructure, our [Solana RPC guide](https://www.alchemy.com/overviews/solana-rpc) 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.
