Skip to content

Databases

Chapter 29: Database Backends (LevelDB, RocksDB, MDBX)

Section titled “Chapter 29: Database Backends (LevelDB, RocksDB, MDBX)”

Blockchain nodes use embedded key-value databases to store blocks, state, and receipts. The database engine you choose determines disk footprint, IOPS pressure, sync speed, and how much memory you need. This chapter compares the real engines used by Ethereum clients and what each tuning lever does.


EngineStructureUsed by (Ethereum)Characteristics
LevelDBLSM treeGeth (default), Reth (legacy)Log-structured, compactions, write-optimized
PebbleLSM tree (Go reimplementation of RocksDB)Geth (optional via --db.engine pebble)Less memory than LevelDB, faster range reads
RocksDBLSM tree (C++, Facebook/FoundationDB)Nethermind, Besu (default), many chainsTunable, high write throughput
MDBXB+ tree (memory-mapped)Erigon, RethRead-optimized, memory-mapped, very low overhead
  • LSM (LevelDB/RocksDB/Pebble) writes log-structured: batched in memory, flushed to immutable sorted files, then compacted in the background. Great write throughput; suffers write amplification (a byte of data may be written several times during compaction).
  • B+ tree (MDBX) updates pages in place inside a memory-mapped file: excellent read performance and predictable IOPS; writes are more expensive per transaction but there are no background compaction storms.
╔══════════════════════════════════════════════════════════════╗
║ LSM WRITE PATH MDBX WRITE PATH ║
║ ║
║ write ──▶ memtable ──▶ SST file ──▶ compaction ──▶ SST ║
║ (batched, "in memory") (immutable) (merge, rewritten) ║
║ ║
║ MDBX: direct page write into the mmap'd B+ tree ║
║ (transaction copies-on-write; readers never block) ║
╚══════════════════════════════════════════════════════════════╝

PropertyLevelDBPebbleRocksDBMDBX
Write throughputMediumHighHighMedium
Read throughput (point)MediumHighHighVery high
Range/iterationSlowHighHighVery high
Background compactionYesYesYes (tunable)No
Memory overheadMediumLowHighLow
Corruption recoveryRerun compaction / resyncSameSamemmap — often recoverable

Operational takeaway: for a busy RPC node, LSM engines burn IOPS on compaction after sync; MDBX shifts the load to reads. That is why Erigon/Reth (MDBX) feel faster on archive queries and why geth offers Pebble to cut memory and compaction cost.


Terminal window
# Default is LevelDB; switch the engine at datadir creation time:
geth --db.engine pebble --datadir /data/ethereum
# ⚠️ --db.engine is read once when the database is created;
# changing it later requires a re-sync.

The old make geth TAGS=rocksdb build path is gone — modern geth ships LevelDB + Pebble only.

Terminal window
# Nethermind: --config mainnet uses RocksDB by default
dotnet Nethermind.Runner.dll --config mainnet --JsonRpc.Enabled true
# Besu: Bonsai trie (reduce storage) with RocksDB backend
besu --data-storage-format=BONSAI --storage-engine=ROCKSDB

Note Nethermind/Besu “Bonsai” is a state storage format (store only the current trie + diffs) — it is orthogonal to the underlying RocksDB vs LevelDB choice.

Terminal window
# MDBX is built in; you mostly tune its file size / pagesize:
erigon --db.size.limit 3tb --datadir /data/erigon

29.4 What Actually Matters for Node Operators

Section titled “29.4 What Actually Matters for Node Operators”
LeverWhat it doesTypical default
--cache (geth)Memory for DB/trie/snapshot caches1024 MB (barely enough)
--db.engine (geth)leveldb vs pebbleleveldb
Compaction settingsLSM only; tune with careengine defaults
WALWrite-ahead log: crash safety at cost of an extra writeon
ulimit -nFDs for thousands of SST filesfix to 65536 (ch47)
SSD/NVMeIOPS ceiling for compactionsNVMe for production
  • iostat -x: %util saturating while CPU is idle → compaction storm or too-small cache.
  • Sync “stuck” while top shows one core pegged → likely LSM compaction (MDBX nodes rarely show this).
  • RPC latency on eth_getBalance/eth_getStorageAt creeping as the trie grows → cache too small or engine read-bound.

“Ethereum clients split into LSM engines (LevelDB/RocksDB/Pebble — write-optimized, background compaction) and B+ tree engines (MDBX — read-optimized, memory-mapped). For an RPC/archive workload I prefer MDBX-based clients (Erigon/Reth); for a system already on geth I enable Pebble and right-size --cache. When the DB becomes the bottleneck I look at IOPS, compaction, and ulimit before throwing RAM at it.”


  • Database choice affects performance
  • MDBX (Erigon/Reth) is fastest for reads; RocksDB/Pebble for writes
  • Geth: --db.engine pebble (set at creation time)
  • LSM engines need IOPS budget for compaction; watch iostat
  • Storage format (Bonsai) is separate from storage engine (RocksDB)

Last Updated: 2026-09-28