Skip to content
BuddingConcept

Aggregate

planted Jan 15, 2024 · last tended Jul 19, 2026

An aggregate is a cluster of entities and value objects treated as one unit for data changes, with a root that guards its invariants. Every change goes through the root, so the invariant holds at the boundary. It often emits a Domain Event when its state changes.

Read through intent and mechanism, the aggregate is an intent (a consistency boundary) welded to a 2003 mechanism (one database transaction, one hand-rolled repository). The intent is durable; the mechanism is the dated part, which is why the aggregate looks more assumption-bound than a bounded context. The field’s sharpest tactical rule, one transaction per aggregate, is a post-Evans elaboration (the 2003 book only implies it) and is itself contested: Vernon allows exceptions, and Millett and Tune go further.

A tactic that ages well: encode invariants in the type system so invalid states will not compile. In Kotlin, a sealed hierarchy does this.

sealed interface Cart {
  data object Empty : Cart
  data class Active(val head: Line, val rest: List<Line>) : Cart
}

Signal: every change to the cluster goes through one root, and the invariant it protects can be stated in a sentence. Part of Domain-Driven Design.

Sources