Some domain concepts have no identity of their own. A price of ₹500 is the same as any other ₹500 — you compare it by its contents, not by a key. Vishwakarma calls these value objects, declared with value. They are embedded directly into entities as typed fields, never stored with their own identity and never referenced by a foreign key.
value — an identity-less domain type
Chowk's money is the archetype: an amount and a currency, compared structurally.
value Money "A monetary amount in minor units (e.g. paise or cents) with its currency." {
amount_minor int64 required
currency Currency required
}Money has no id. Two Money values with the same amount and currency are interchangeable — that is the whole point of a value object. It is embedded into an entity simply by naming it as a field's type:
price Money required // on Product
total Money required // on OrderUnder the hood it lowers to a nested structure on the row, not a joined table. There is no Money table, no money_id foreign key — the amount and currency live directly on the product and the order.
A value object can carry its own rules
A value object is a real modeling unit, not just a field group: it can validate its own contents. Chowk's shipping address embeds a shape rule on its postal code:
value Address "A postal shipping address." {
line1 string required
line2 string?
city string required
postal_code string required specs [PostalCode]
country string required
}line2 is optional (?); postal_code carries specs [PostalCode], a reusable shape rule covered in Field specs. Wherever an Address is used — as Order.shipping_address, say — the postal-code rule travels with it. The value object owns its own validity.
value versus object
There is a second business-object keyword, object, with the same grammar but different intent. Use value when the type's identity is its content (money, an address, a coordinate). Use object for a structured payload where value-equality is not the point — a message, a request bundle. Chowk models a gift message as a plain object:
object GiftMessage "A gift message a customer can attach to an order." {
message string required
signed_by string
}A gift message is attached to an order (Order.gift_message), but two identical gift messages are not conceptually "the same message," so it is an object, not a value. The distinction is a documented signal of intent — the compiler records each as a different semantic kind — and it keeps your model honest about which types are values and which are merely structured data.
Declare once, reuse across sub-domains
A value object declared in one sub-domain is reused in others with use. Money lives in catalog and is imported by ordering:
use catalog.MoneyFrom there Order.total and OrderLine.unit_price are the same Money value object as Product.price. One definition, one shape, one set of rules — shared across bounded contexts without duplication. That is the payoff of modeling a value explicitly instead of scattering an amount and a currency column across every table that needs a price.