Value objects

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.

sub-domains/catalog/business_objects/money.vishwakarma
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 Order

Under 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:

sub-domains/ordering/business_objects/address.vishwakarma
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:

sub-domains/ordering/business_objects/gift_message.vishwakarma
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.Money

From 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.