Architecture & System Design › Domain-Driven Design
Aggregate Root
The single entry point for modifying an aggregate.
Also known as: aggregate root, root entity, consistency root
The Aggregate Root is the aggregate’s sole entry point: the one entity outsiders may hold references to, through which all mutation flows, and which enforces every invariant of its cluster. Roots carry global identity; everything inside is reachable only by navigating from the root.
order = OrderRepository.find(id) // root by global id
order.addLine(item) // root enforces invariants (credit, stock, totals)
orderLine (no repository, no outside refs, no direct mutation)
Roots own the transactional boundary (one aggregate per transaction, as a rule), publish the aggregate’s domain events, and guard cross-aggregate references (by id only, never object links). Their methods read as business operations, not CRUD.
The classic mistakes:
- Multiple entry points. Repositories or APIs exposing internal entities let outsiders bypass root invariants. One root, one door, enforced.
- Setters instead of operations.
order.setStatus(x)exposes state transitions callers shouldn’t choose;order.ship()/order.cancel()enforce valid transitions with their rules. - Cross-root object references. Holding direct links to other aggregates’ internals (or roots as navigable objects) tangles lifecycles and transactions. Reference by id; resolve when needed.
- Transaction spanning roots. Atomicity across aggregates fights the pattern (and scalability); use domain events plus eventual consistency between roots.
- Root bloat. Every operation hanging off the root (fifty methods) signals oversized aggregates or misplaced domain services. Split aggregates; extract services for cross-cutting logic.
- Events unreleased. State changes without published domain events blind downstream contexts. Roots emit; infrastructure delivers.
- Identity confusion. Root identity global and long-lived; internal entities identified locally (or by value). Mixing scopes corrupts references.
How to design them: single entry, behaviour-rich operations, invariants enforced, events emitted, references by id outward. The root is the aggregate’s guardian — small, strict, and the only way in.