@defaultAlways
Set a default value that resets on every write — create and update — when the field is not explicitly provided.
Sets a default value for a field that is re-applied on every write (create and update) when the field is not explicitly provided. This is the general-purpose version of SurrealDB's DEFAULT ALWAYS mechanism.
Syntax
@defaultAlways(value)Supported Value Types
| Value | Example | Description |
|---|---|---|
| String literal | @defaultAlways("dirty") | Default string value |
| Integer literal | @defaultAlways(0) | Default integer value |
| Float literal | @defaultAlways(1.5) | Default float value |
true / false | @defaultAlways(false) | Default boolean value |
null | @defaultAlways(null) | Default to null (requires @nullable) |
When to Use
@defaultAlways is for fields whose value should reset to a known default on every update unless explicitly overridden. Common use cases:
- Review gates — any edit to a record should require re-review
- Sync/dirty flags — any modification marks the record as needing sync
- Retry counters — reset to zero after each update
Unlike @default, which only fires on create, @defaultAlways resets the field on every update where the field is omitted. This can be surprising if you expect a value to persist across updates. Only use it when the "reset on every write" behavior is intentional.
Basic Usage
model Article {
id Record @id
title String
content String
reviewed Bool @defaultAlways(false)
needsSync Bool @defaultAlways(true)
}// Create — @defaultAlways fields auto-filled when omitted
const article = await client.db.Article.create({
data: { title: 'Draft', content: 'Hello' },
});
// article.reviewed === false
// article.needsSync === true
// Override on create — your value is respected
const article2 = await client.db.Article.create({
data: { title: 'Pre-approved', content: '...', reviewed: true },
});
// article2.reviewed === true
// Update — omitted @defaultAlways fields reset to their default
await client.db.Article.updateUnique({
where: { id: article2.id },
data: { content: 'Edited content' },
});
// reviewed resets to false (content was edited, needs re-review)
// needsSync resets to true (record was modified)
// Update — explicit value overrides the reset
await client.db.Article.updateUnique({
where: { id: article2.id },
data: { content: 'Minor fix', reviewed: true },
});
// reviewed stays true (explicitly provided)How It Works
@defaultAlways(value) generates DEFAULT ALWAYS value in SurrealDB. On updates, Cerial automatically injects field = NONE for any @defaultAlways field not present in the update data. This triggers SurrealDB's DEFAULT ALWAYS mechanism to re-apply the default value.
Without this NONE injection, the existing value would be preserved — the "reset on every write" behavior requires Cerial to actively clear the field so the default kicks in.
Object Fields
@defaultAlways can be applied to fields within object definitions:
object ReviewMeta {
note String @defaultAlways("pending review")
flagged Bool @defaultAlways(false)
}
model Document {
id Record @id
title String
meta ReviewMeta?
}When an object has @defaultAlways fields, Cerial generates a ReviewMetaCreateInput type where those fields are optional. On merge-style updates, omitted sub-fields are reset via dot-notation NONE injection.
// Create — sub-fields auto-filled
const doc = await client.db.Document.create({
data: { title: 'Report', meta: {} },
});
// doc.meta.note === "pending review"
// doc.meta.flagged === false
// Merge update — omitted sub-fields reset
await client.db.Document.updateUnique({
where: { id: doc.id },
data: { meta: { note: 'needs revision' } },
});
// meta.note === "needs revision" (explicitly provided)
// meta.flagged === false (reset by @defaultAlways)Tuple Elements
@defaultAlways can also be applied to individual tuple elements:
tuple SyncState {
retries Int @defaultAlways(0),
dirty Bool @defaultAlways(true)
}
model Job {
id Record @id
sync SyncState
}Tuple elements with @defaultAlways are optional in create input and reset on every update when omitted.
Allowed On
| Construct | Allowed |
|---|---|
| Model fields | ✅ |
| Object fields | ✅ |
| Tuple elements | ✅ |
| Enum values | ❌ |
| Literal fields | ❌ |
Mutual Exclusions
@defaultAlways cannot be combined with any of these decorators on the same field:
@default— use one or the other@createdAt,@updatedAt,@now— timestamp decorators each set their own default@uuid,@uuid4,@uuid7— UUID auto-generation decorators@readonly—@readonlyprevents updates, which contradicts@defaultAlwaysresetting on every write
Comparison
| Decorator | Stored | Set on create | Reset on update | Can override | Field types |
|---|---|---|---|---|---|
@default(value) | Yes | Yes (when absent) | No | Yes | Any |
@defaultAlways(value) | Yes | Yes (when absent) | Yes (when absent) | Yes | Any |
@updatedAt | Yes | Yes (time::now()) | Yes (time::now()) | Yes | Date only |
@createdAt | Yes | Yes (time::now()) | No | Yes | Date only |
@now | No | N/A (computed) | N/A (computed) | No | Date only |