ETH2QS · sync-lab

Field report · six weeks · mainnet

The fastest Ethereum client is one almost nobody runs.

A head-to-head bake-off of seven execution clients and five consensus clients — the same mainnet sync, on the same host, one client at a time — run end-to-end by a fleet of AI agents.

eth2quickstart.com  ·  2026-06-22 → 2026-08-03 (initial campaign to 07-14; steady-state + restart phase after)

The rig

One host. One client at a time. Two numbers each.

Every client got a fair shot: its most disk-efficient mode, a fixed consensus partner, and a hard 72-hour cap. We recorded the final synced disk footprint and the sync duration — then watched what happened on restart.

7
Execution clients
5
Consensus clients
72h
Cap per candidate
1
Shared host, no MEV, no keys

Result 01 · disk footprint

Disk: the field converges — there's no winner.

Nimbus-eth1
~40 GB · only ~21% synced
Ethrex
~470–476 GiB · no-history
Reth
~0.98 TiB · capped
Nethermind
~1.06 TiB · steady-state
Besu
~1.08 TiB · un-pruned
Geth
~1.13 TiB · baseline
Erigon
~1.21 TiB · no-sync
0 ————————————————— 1.3 TiB

The field converges — no disk winner. Nethermind, besu, and geth all land in the same ~1.0–1.2 TiB band once they carry full post-merge history; nethermind's early snap-sync-tip read (~251 GiB) predates that backfill. Disk size here is a config knob, not a client-efficiency signal. The hatched bars aren't comparable: Nimbus-eth1's ~40 GB is only ~21% of a sync, and Ethrex's ~470–476 GiB is a settled plateau, not a pruned-comparable footprint — it's smaller only because it's a no-history node, not because it's more efficient.

Result 01 · the disk lever

…but you can turn the knob down.

Nethermind minimal
~250–280 GiB · no history · new default
Ethrex
~470–476 GiB · no history
Nethermind full
~1.06 TiB · with history
Geth
~1.13 TiB · floor, can't go lower
0 ————————————————— 1.3 TiB

Config-determined cuts both ways. Drop post-merge history and nethermind's new default lands at ~250–280 GiB — the smaller of the two no-history configurations we measured, roughly half ethrex's no-history datadir and a floor geth can't reach (not a perfectly controlled comparison — different state encodings). The price is no historical RPC (old blocks return null); NETHERMIND_FULL_HISTORY=true on a fresh/rebuilt datadir keeps full history for a public RPC. A within-tier win, not "4× leaner than geth" — that would score a no-history node against a with-history one.

Result 02 · cold-sync speed

ethrex wins speed — by a lot.

ethrex
2h 16m · fastest
geth
8h 28m
nethermind
~14h 30m
besu
19h 18m
0 ————————————————— 20 h

Completed syncs only. ethrex finished nearly 4× faster than the next client. So why does almost nobody run it?

The paradox

ethrex hits a hard restart cliff.

Gaps through 23 minutes resumed; a 26-minute gap stalled. In measured 1.5–2-hour gaps, ethrex discarded its synced state and re-synced from scratch (~2h) — an operability tax that helps explain why the fastest-syncing client has close to zero real-world mainnet adoption.

~128
blocks — the cliff edge
~25 min
downtime before stall onset
~2 h
to re-sync from scratch

Bisected with controlled stop → wait → start cycles: clean resume at 12 / 20 / 23 min gaps; stuck at 26 min.

The under-reported axis

Restart resilience is a third axis nobody benchmarks.

Sync speed and disk footprint are easy to measure and easy to publish. How a client behaves after downtime is neither — and it's the axis that most cleanly explains which clients people actually keep running.

Clean resume

geth, nethermind

Pick up where they left off. Boring, in the best way — both now directly measured (geth 2026-07-10, nethermind 2026-08-01).

Re-snap cliff

ethrex

Stops resuming beyond ~25 minutes; longer measured gaps triggered a full re-snap.

Mid-sync deadlock

besu

A prolonged stale-CL outage aged out the pivot; the downloader died while RPC stayed up.

Execution-client scorecard

The full field.

ClientResultSyncFootprintMainnet
Nethermindsynced~14.5h~1.06 TiB36.0%
Gethsynced8h28m~1.13 TiB44.9%
Ethrexsynced2h16m~470–476 GiB, no-history~0%
Besusynced19h18m~1.08 TiB · un-pruned17.4%
Reth72h cap~0.98 TiB*1.5%
Nimbus-eth172h cap~40 GB*~0%
Erigonno-syncdeadlock~1.21 TiB · frozen~0%

Disk converges once full post-merge history is counted (nethermind ~1.06 TiB, besu ~1.08 TiB, geth ~1.13 TiB) — no meaningful ranking there. Ethrex plateaus at ~470–476 GiB but isn't comparable (no-history node); reth & nimbus-eth1 are full-sync-only, capped here. * partial

Consensus layer

The CL layer looks solved — on the axes we measured.

All five checkpoint-synced to a validating head in minutes — ~6–9 min on the geth anchor, ~7–10 min on the nethermind anchor, ~22–23 min on ethrex — with zero client-fault failures. Sync time is a tie, so footprint is the differentiator. Scope: we swept the five for sync and footprint, not for restart-resume — the only CL we restart-tested is prysm, the constant anchor.

lodestar
~177 MiB · smallest
lighthouse
~518 MiB · lean default
grandine
~725 MiB
teku
~936 MiB
nimbus
~1.2 GiB · largest

The same three tiers — lightweight, mid, heavy — held across three EL anchors — EL/CL decoupling, supported empirically (lodestar and lighthouse swap which is smallest, by anchor).

Methodology

Run by agents — governed by humans.

A three-tier hierarchy kept the token cost sane and the judgment where it belonged:

OrchestratorClaude Opus — plans, reviews every diff, writes the durable state. Doesn't hand-write client code.
↓ dispatch  ·  ↑ summary only, not full context
BuildersFresh Sonnet subagents — one task each, report a short summary back.
DelegatesCheaper / sandboxed models — read-only research, routed through wrapper binaries.

Governance, non-negotiable: one candidate at a time · destructive actions human-gated · conventional commits · an agent cannot merge its own PR.

The machine that kept us honest

Two clocks, and a gate.

Decouple the clocks

Node vs agent time

Nodes sync for 72h in detached systemd; the agent sleeps and wakes on decision-worthy events, not polling logs.

Durable state

Small files, not context

Conclusions pushed down to markdown + CSV so a fresh session recovers the run — no context-window bottleneck.

Config-optimality gate

Fair by construction

Before a result counts, the harness verifies the client ran its most disk-efficient mode — else it rejects the run, not the client.

~1,550
lines of shell — the whole harness

A real benchmark, not a lab result: shared semi-production host, footprint from the final near-cap sample — never a mid-sync peak.

Four incidents, all caught & documented

What actually breaks in the first 23 days.

nethermind

13.3h silent stall

Head frozen at block 4,651, 0 peers — everything else looked healthy. Root cause: P2P pinned to loopback. Fixed by advertising a routable external IP.

besu

Mid-sync deadlock

Downloader thread died, process stayed alive and kept answering RPC. Stale pinned CL stalled the beacon past the servable window.

ethrex

Restart-resync cliff

Stalled just beyond ~25 min; longer measured gaps discarded state and re-snapped. Inherent to the current design.

erigon

Gap-close deadlock

OtterSync + a checkpoint-synced CL never issue the forkchoice update that would close the gap. Raising the CL CPU cap 200%→600% advanced it ~5k blocks, then it re-froze.

If you run one node for the long haul

What to actually run.

  • Diversity pick → Nethermind. Compact flat-storage state, restart-resume now measured (2026-08-01: closed a 10,607-block/~35h gap in 35m09s, no re-snap), and a minority-client diversity bonus — on disk it's on par with geth (~1.06 vs ~1.13 TiB) once full post-merge history is counted, not the space-saver its snap-sync-tip snapshot suggested. It now ships minimal-history by default — ~250–280 GiB, the smaller of the two no-history configurations we measured, if you don't need historical RPC (NETHERMIND_FULL_HISTORY=true keeps full history for an RPC provider). Costs a bit more sync time (~14.5h vs geth's ~8.5h).
  • The boring default → Geth. Largest ecosystem, most docs, cleanest ~8h28m snap sync — its ~1.13 TiB disk footprint is on par with the rest of the field, not a downside unique to geth.
  • Consensus → Lighthouse. The lean, safe default: ~518 MiB on the geth anchor, checkpoint-syncs in minutes, blob pruning on by default.

The real lesson: operational risk in an Ethereum node lives in the execution layer, not the consensus layer.

Read the whole thing

The numbers, the harness, and every gotcha — on-site.

eth2quickstart.com/blog

One-line install → hardened Ethereum node, 12 clients, MEV integration. github.com/chimera-defi/eth2-quickstart

← → navigate  ·  N notes  ·  P print / PDF
SLIDE 01 / 14

Speaker notes