Lesson 6 — Reth vs Geth / Alloy vs ethers-rs — the substitution case
Question
Reth targets to replace Geth (Go). Alloy targets to replace ethers-rs (the earlier Rust library). Why replace existing things? Performance + design + maintenance — three axes that justify the substitution.
Principle (minimum model)
- Reth vs Geth — performance. Reth's performance case is architectural: a staged-sync pipeline that batches I/O, MDBX + static files for storage, and parallel work around execution (sender recovery, prewarming, state root). Benchmarks vary by hardware, chain and version, so measure on your own workload rather than trusting a single multiplier.
- Reth vs Geth — modularity. Reth SDK turns a full node into an SDK. Pool / payload builder / network / EVM executor / consensus are swappable node components → Tempo (payments L1), Berachain (
bera-reth) and Base (base/base) build on it. Geth is reused mainly by forking the whole codebase. - Alloy vs ethers-rs — design. Alloy is Network-generic (Ethereum / Optimism / custom L2 all under one type system) +
Providertrait +TxFillerstacking. ethers-rs baked Ethereum's types into its core (with feature-flagged extras such as Celo); extensibility differs structurally. - Alloy vs ethers-rs — maintenance. ethers-rs was officially deprecated in favour of Alloy (gakonst/ethers-rs#2667, November 2023) and the repository is now archived. Alloy is actively developed with Paradigm's backing; the ecosystem has migrated.
- Substitution timing. New projects → Reth + Alloy recommended. Existing Geth / ethers-rs projects → migrate based on cost-benefit; Foundry depends on Alloy (no ethers-rs), and Reth itself, Tempo and Base are built on Alloy.
Worked example + steps
Reth vs Geth / Alloy vs ethers-rs — the substitution case
You've placed the projects on a map. Now the next-most-asked question: why are teams actively migrating off the older alternatives? Geth has run Ethereum for a decade. ethers-rs was the Rust Ethereum library for years. Yet new infrastructure is being built on Reth and Alloy. This lesson is why — substitution by substitution.
1. Reth vs Geth
Geth (Go-Ethereum) is the original execution client. It's run mainnet since 2015, still holds the largest execution-client share, and the team behind it is excellent. Reth is not "Geth but better." It's a different design that earns its place by what Geth structurally can't do.
| Property | Geth | Reth | Why it matters |
|---|---|---|---|
| Language | Go | Rust | Cargo workspaces let you import revm as a library and use it standalone. Geth's core/vm is importable as a Go package too, but it is wired to Geth's own StateDB, so reuse in practice means forking go-ethereum. |
| Architecture | Tightly coupled | Modular crates (revm, alloy, reth-stages, reth-network, reth-rpc, etc.) | You can fork one crate (e.g., custom executor) without forking the entire node — central to the App-chain / L1 fork pattern. |
| State storage | Key-value store (Pebble by default, LevelDB still supported), path-based state scheme | MDBX (memory-mapped B+tree) for state + static files for headers / transactions / receipts | A B+tree has no LSM-style background compaction, which keeps read latency predictable; append-only history lives in flat static files. |
| Execution engine | go-ethereum's interpreter | revm (Rust, library-first) | revm is reused by Foundry, MegaETH's mega-evm, Hyperliquid's public HyperEVM replay tool (hyper-evm-sync) and Rust MEV stacks. Geth's interpreter travels mostly inside Geth forks (BSC, Polygon Bor, ...). |
| Sync strategy | Snap sync | Staged sync (a pipeline of ~15 stages, StageId::ALL in crates/stages/types/src/id.rs) | Staged sync amortizes I/O across whole batches and is easy to extend with custom stages. |
| Extension API | Live-tracing hooks (core/tracing, eth/tracers/live) | ExEx (Execution Extensions) — in-process Rust tasks fed committed / reorged / reverted chains | Build node-speed indexers, MEV bots, risk engines inside the node, no RPC round trips. Geth's hooks observe execution; ExEx gets whole executed chain segments plus reorg notifications and can drive pruning via its finished height. |
| Chain forking | Hard (entire fork-of-Geth) | Easier (Reth SDK: swap components, keep the rest) | Tempo (tempoxyz/tempo), Berachain (bera-reth), Base (base/base) and OP Stack's op-reth use this pattern; community HyperEVM archive nodes (nanoreth) do too. |
| Reuse footprint | Geth's code is reused mostly as Geth forks | Reth's components (revm, alloy, reth-* crates) are published crates other projects depend on | Most Rust EVM tools you'll touch are built on top of one of these crates. |
Concretely: a team shipping a payments-priority L1 with custom transaction ordering builds on Reth — and doesn't even fork the whole thing. Tempo depends on Reth's crates (pinned to a git rev) and plugs its own components into Reth's ComponentsBuilder: TempoPoolBuilder, TempoPayloadBuilderBuilder, TempoNetworkBuilder, TempoExecutorBuilder, TempoConsensusBuilder (crates/node/src/node.rs). Everything else — storage, RPC, sync, engine tree — is Reth's. With Geth they'd fork the whole codebase and accept the rebase tax forever.
Reth wasn't built to dethrone Geth. It was built to be the substrate the next generation of chains builds on. That's a different category.
2. Alloy vs ethers-rs
ethers-rs was the Rust Ethereum library from ~2020 to 2023. Then in November 2023, ethers-rs (created by Georgios Konstantopoulos, now at Paradigm) was deprecated in favour of Alloy (#2667); the repo is archived. The migration wasn't gradual or aesthetic — it was a deliberate redesign with specific properties ethers-rs structurally couldn't deliver.
| Property | ethers-rs | Alloy | Why it matters |
|---|---|---|---|
| Modularity | Monolithic crates | Many small crates (alloy-provider, alloy-network, alloy-primitives, alloy-signer, alloy-rpc-types, ...) | You pull in only what you need; Cargo bloat shrinks dramatically. |
| Async style | async-trait on Middleware (boxes every future) | Provider still uses async-trait for many methods, but common RPC calls (get_block_number, get_balance, ...) return ProviderCall / RpcWithBlock futures by value | Fewer per-call allocations on hot RPC paths, plus builder-style options (.block_id(..)) before awaiting. |
| Multi-chain | Ethereum types baked in (Celo support behind a feature flag) | Network trait abstracts chain primitives | Same Provider code works on Ethereum, Optimism, custom L2s — the Alloy source-reading course walks this. |
| Type ergonomics | Its own types (ethers::types), separate from revm | alloy-primitives Address, U256, B256 — which revm re-exports (revm-primitives: pub use alloy_primitives::{...}) | One set of types across alloy + revm + reth. No conversion boilerplate. |
| Wallet / signer composability | Signer as one more Middleware layer | Signer / NetworkWallet + TxFiller compose via ProviderBuilder | Custom signing, nonce management, gas estimation layer cleanly. The Alloy source-reading course's Signer chain teaches this. |
Procedural macros (sol!) | abigen! generating bindings from JSON ABI | sol! (alloy-sol-types) parses Solidity syntax directly, used throughout alloy | Define Solidity types in Rust at compile time; no manual ABI structs. |
| Maintainership | Deprecated (Nov 2023), repo archived | Paradigm-backed project + community | Active development and releases. |
If you're writing a new MEV searcher in 2026, you'd choose Alloy because (a) you share types with revm (and your fork simulation lives in revm), (b) you can compose your own Signer with cloud KMS or hardware without rewriting the Provider, (c) your code runs on Optimism / Base / any Reth-based L2 with one type parameter change, and (d) ethers-rs is deprecated and archived, so it gets no fixes at all. Inertia is the only reason to stick with ethers-rs, and inertia gets weaker every quarter.
3. The pattern across both substitutions
Geth and ethers-rs are not bad. They're products of an earlier moment in the Rust EVM ecosystem — when the priority was "make it work" rather than "make it composable across N downstream projects."
Reth and Alloy share a deliberate design choice: composability over completeness. Both expose internal pieces as library crates that downstream projects can mix, match, and replace. Geth and ethers-rs were designed as products to be consumed; Reth and Alloy are designed as substrates to be extended.
This is the structural reason the rest of this curriculum exists. The source-reading courses that come next — Revm, Reth, Alloy — teach you to read the substrate. Once you can read it, you can build on it. That's the leverage Geth and ethers-rs structurally couldn't offer.
Two reads of the same pattern: payments-priority L1s fork Reth instead of Geth because Reth's crates compose; new MEV searchers pick Alloy over ethers-rs because Alloy shares types with revm and stays maintained. Both are decisions about substrates versus products — keep that lens for the rest of the curriculum.
Next up
With this lesson, Module 0 is complete: the systems-engineering frame from lesson 0, the project map (Reth / Revm / Alloy), the Solana / Solidity onramps, and now the substitution case. Module 1 sets up Rust on your machine so you can start reading source. The frame from lesson 0 starts paying off the moment you open the first alloy-rs/alloy file.
Summary (3 lines)
- Reth vs Geth: staged-sync + storage architecture + SDK modularity (Tempo / Berachain / Base as case studies). Alloy vs ethers-rs: Network-generic design + active maintenance; ethers-rs deprecated (Nov 2023) and archived.
- New projects → Reth + Alloy. Existing Geth / ethers-rs migrate based on cost-benefit. Foundry, Reth, Tempo and Base already run on Alloy.
- Module 1 next: Rust environment setup (rustup + VS Code + rust-analyzer).