Table of Contents

Storage Modes

Pick durability and write cost per component type — from microsecond ACID to nanosecond scratch memory, in one engine.

Status: ✅ Implemented · Visibility: Public · Level: 🟢 Start Here · Category: Ecs

🎯 What it solves

Game and server workloads mix data with wildly different needs: a position updated every tick can tolerate losing a few frames, while inventory or currency can never be lost or read half-written. Forcing all of it through one storage tier means either paying full ACID cost for high-frequency data or risking real state on a fast-but-loose tier. Storage Modes let each component type — not the whole database — declare its own point on the durability/performance spectrum, so a single entity can mix a Versioned wallet with a SingleVersion position and a Transient animation cursor.

⚙️ How it works (in brief)

StorageMode is set via [Component(StorageMode = ...)] and is fixed for a given (component name, revision): changing how a component is stored requires bumping the [Component] revision — re-using the same revision with a different mode throws InvalidOperationException on reopen. Versioned keeps a full MVCC revision chain (snapshot isolation, zero loss); SingleVersion stores one in-place HEAD slot with WAL tick-fence durability (≤1 tick loss); Transient is heap-only and never persisted. All three are read and written through the same EntityRef.Read<T>() / Write<T>() calls — only the cost and guarantees differ, not the API. A runtime durability discipline (Committed) layers commit-time, zero-loss atomicity onto the SingleVersion layout without paying for a revision chain.

Sub-features

Sub-feature Use it for Write cost (Zen 4) Durability
Versioned Inventory, economy, progression, anything needing snapshot isolation or AS-OF reads ~250 ns Zero loss, full ACID
SingleVersion (Tick-Fence Durability) Position, velocity, health, cooldowns — high-frequency, loss-tolerant ~40 ns ≤1 tick loss
Transient Animation state, input buffers, pathfinding scratch, targeting info ~40 ns None — gone on crash
Committed Durability Discipline A SingleVersion write that must be atomic and zero-loss without MVCC (teleport, item pickup, currency debit) ~40 ns + commit publish Zero loss, atomic, no chain

⚠️ Guarantees & limits

  • StorageMode is fixed for a given (name, revision); changing a component's mode requires a new [Component] revision (there is no in-place mode migration yet — tracked in #546).
  • An entity can freely mix component types across all three modes (Spawn/Open/OpenMut/Destroy work uniformly); rollback semantics differ per mode — see each sub-feature.
  • Indexes, spatial queries, and ECS lifecycle (Spawn/Destroy/Enable) are available in all three modes, but with different freshness/synchronicity guarantees — check the Storage Mode Feature Matrix (linked below) before committing to a mode.
  • The mode choice is silent at the API level — picking Versioned for scratch data overpays, picking SingleVersion for currency under-protects. There is no compiler or runtime guard for "wrong mode for this data."

🧪 Tests