Collections
A collection is a named, typed set of records. Collections are the data store for the domain — every write in the system targets a collection, and every projection reads from one.
Defining fields
Fields are declared with a name and a type. The ! suffix marks a field as required.
domain:
collections:
messages:
fields:
id: id!
text: text!
user_id: id!
channel: text
created_at: timestamp!
Available field types:
| Type | Description |
|---|---|
id | Unique identifier |
text | UTF-8 string |
int | Integer |
float | Floating-point number |
bool | Boolean |
timestamp | ISO 8601 datetime |
object | Nested key-value object |
A field declared without ! is optional and may be null.
Invariants
Invariants are structural rules enforced at every write. A write that violates any declared invariant is rejected before it reaches the database.
domain:
collections:
messages:
fields:
id: id!
text: text!
created_at: timestamp!
invariants:
on_fail: abort
structural:
- description: "Message text must not be empty."
rule:
"!==":
- var: text
- ""
on_fail: abort is the only supported mode. Invariants are hard constraints — there is no soft-fail path. If an action step produces a write that would violate an invariant, the entire action is aborted.
Invariant rules use the $expr DSL. The var operator references a field by name on the record being written.
Nested object fields
The object type supports nested structure. Nested fields are declared inline.
domain:
collections:
hello_messages:
fields:
id: id!
moderation:
object:
status: text!
checked_at: timestamp
flagged_reason: text
Object fields are accessed in $expr using dot paths: var: moderation.status.
What writes to collections
Only actions write to collections, via the collections.write provider capability. Projections, flows, and domain capabilities are all read-only. This is enforced at compilation — a projection or flow that references collections.write is a compilation error.
What reads from collections
Projections read from collections via the runtime. The specific scan, filter, and join operations a projection performs are declared in its strategy, not in the collection definition.
What's next
- Actions: the only writers to collections
- Projections: reading and deriving views from collections