Skip to content

Aggregates

An Aggregate is a key pattern in Domain-Driven Design (DDD) used to group related entities and value objects under a single, consistent unit.

It ensures:

✅ Business rules are enforced within a boundary.
✅ Changes are applied consistently.
✅ External systems interact only through well-defined roots.


An aggregate:

  • Is a cluster of related domain objects (entities, value objects).
  • Has one root entity (the Aggregate Root) that controls access and modifications.
  • Guarantees consistency inside the boundary — outside systems must go through the root.

Example:

  • An Order aggregate contains:
    • The Order entity (aggregate root).
    • A list of OrderItem entities (part of the aggregate).
    • A PaymentStatus value object.

All modifications to OrderItem go through the Order — external systems never manipulate items directly.


export class OrderItem {
constructor(
public readonly productId: string,
public quantity: number
) {}
}
export class Order {
private items: OrderItem[] = [];
private isPaid: boolean = false;
constructor(public readonly orderId: string) {}
addItem(item: OrderItem) {
this.items.push(item);
}
pay() {
if (this.items.length === 0) {
throw new Error('Cannot pay for an empty order.');
}
this.isPaid = true;
}
getItems(): OrderItem[] {
return [...this.items];
}
isOrderPaid(): boolean {
return this.isPaid;
}
}

✅ Only the Order (aggregate root) exposes methods to modify or query the state.


  • Enforce business invariants inside the boundary.
  • Simplify external interactions (only talk to aggregate root).
  • Improve maintainability by clarifying internal vs external responsibilities.

  • Making aggregates too large — keep them small and focused on consistency boundaries.
  • Allowing external systems to modify child entities directly.
  • Not clearly defining the aggregate root.

DomusJS does not enforce aggregates, but:

  • You can design your domain models to follow this pattern.
  • Combine with value objects, domain events, and services inside each bounded context.
  • Use aggregates to enforce consistency before publishing events or persisting data.