An immutable object defined by its attributes
A value object is a domain object defined entirely by its attributes, with no identity of its own. Two value objects with the same attributes are the same value, the way two £5 notes are interchangeable. It carries no thread of identity through time, it is immutable once created, and changing it means making a new one. The discipline it brings is precision: a Money or a DateRange becomes a small, self-validating thing that cannot be in a nonsensical state.
Eric Evans named the value object in Domain-Driven Design (Addison-Wesley, 2003), pairing it with the entity as the two ways a domain object can be classified. An entity has identity that persists through change; a value object has no identity and matters only as the combination of its attributes. Evans's guidance was to treat value objects as immutable and to compare them by value, so that equality means equal attributes rather than the same memory location.
Martin Fowler had been circling the same distinction. His EvansClassification entry credits Evans with making the entity-and-value-object split a clean, teachable rule, and Fowler's own ValueObject note reinforces equality by value and immutability as the defining traits. The two ideas, no identity and no mutation, turn out to be linked: if a value can never change, sharing it is safe, and identity stops mattering.
The pattern earned its keep against primitive obsession, modelling a quantity as a bare decimal or a string. Wrapping currency-and-amount into a Money type, or a start-and-end into a DateRange, lets the object reject invalid states at construction and own the operations that belong to it. The community settled on a default: prefer value objects, reach for entities only when something genuinely needsNeedUserA user need, pain, desire, or constraintView reference → to be tracked as the same thing over time.
A booking system models a stay as a DateRange value object holding a check-in and a check-out date. The constructor refuses a range where check-out precedes check-in, so an invalid stay cannot exist anywhere downstream. The object owns the behaviour that depends on its values: nights(), overlaps(other), contains(date). None of these mutate it; extend(byNights) returns a new DateRange.
Two guests booking the same Friday-to-Sunday window hold two ranges that are equal by value, and the system treats them as the same stay length without caring that they are separate instances. Compare this with the Booking entity that wraps the range. Two bookings for that identical window are emphatically different bookings, because a booking has identity: a reference, a guest, a lifecycle. The range is a value; the booking is a thing.
In the Unified Product Graph, a value object is an engineering-region entity for an attribute-defined, immutable concept in the domain model. The AggregatecontainsValue Objecthierarchy edge ties it to the aggregate that holds it, recording it as part of that consistency boundary while keeping it distinct from the identity-bearing entities alongside it. Modelling value objects separately keeps the line between identity and value queryable, so a reader can see which parts of a model are tracked things and which are interchangeable values, the distinction Evans drew and the one teams most often blur.aggregate_contains_value_object
Type-specific fields on BaseNode
immutablebooleanWhether immutable
equality_fieldsstringFields used for equality
idstringrequiredUnique identifier (UUID)
typeNodeTyperequiredDiscriminator for the entity type
titlestringrequiredDisplay name
descriptionstringOptional detailed description
statusstringLifecycle status
tagsstring[]Freeform tags for filtering
1 edge type connected to this entity.
aggregate_contains_value_object