Entity-Component-System architecture grew up in game engines; relational databases grew up in enterprise software. They never compared notes. Loïc Baumann — who worked on Unity’s DOTS and is now VP of engineering at MEGA — lays out how the two converged anyway, and argues that game servers are the place the mismatch finally has to be resolved: they need engine-grade throughput and database-grade guarantees in the same process.

His mapping is the whole thesis in five lines:

  • An ECS archetype is a table
  • A component is a column
  • An entity is a row — a 64-bit ID with no inherent structure
  • A system is a query
  • A 16 ms frame budget is a latency SLA

Both traditions landed on the same structures because the underlying physics is the same: data has to be laid out for the CPU cache, access patterns have to be predictable, and the latency budget is real. What engines know that databases drifted away from:

  • Cache locality by default. A row store loading player positions drags names, inventories and health along with it. Components stored per type make that scan linear, with every byte useful. The framing number: an L1 hit costs about 1 ns, a DRAM miss 60–70 ns.
  • Zero-copy as the default, not the optimization. Blittable structs read straight from pinned memory pages — no deserialization, no heap allocation, no GC.
  • Entity as pure identity. State lives in typed component storage, which is what makes per-component versioning, storage modes and indexes possible at all.

And what databases know that engine code usually skips:

  • MVCC per component, not per row. Snapshot isolation with readers never blocking writers — and updating an entity’s position does not create a new version of its inventory.
  • Selective access. Servers act on a small slice of entities per tick: roughly 1–4% for battle royale relevancy, 0.2–1% for MMO areas of interest. Iterating everything is 25–100× the necessary work. Unity DOTS enableable components, Flecs group_by and Unreal’s MassEntity LOD tiers are all described as workarounds for the fact that ECS was built for bulk iteration.
  • Indexes as first-class citizens. B+Trees on marked fields, a two-layer spatial index (sparse grid over a page-backed R-tree) for area-of-interest queries, and a query planner that picks scan versus seek on estimated selectivity.
  • Durability matched to the data. WAL recovery for state that cannot be reloaded, per-component storage modes (versioned, single-version, transient), and durability chosen per operation — deferred for position ticks that can be re-simulated, immediate fsync for the drop worth real money.

The trade-offs are stated plainly rather than buried: components must be blittable (fixed-size strings, no object references), relationships follow entity links rather than SQL joins, and schema lives in code instead of DDL.

The idea worth taking, whatever engine you run, is granularity. Version, persist and index each component type by what it actually needs, instead of applying one durability policy to everything — most of the architecture here is just that decision applied consistently.

Worth a caveat: this is post two of ten in a series for the author’s own database engine, so the performance claims are his. The convergence argument and the per-component design reasoning hold up on their own.