Cerial
DecoratorsDefault

@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

ValueExampleDescription
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

ConstructAllowed
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@readonly prevents updates, which contradicts @defaultAlways resetting on every write

Comparison

DecoratorStoredSet on createReset on updateCan overrideField types
@default(value)YesYes (when absent)NoYesAny
@defaultAlways(value)YesYes (when absent)Yes (when absent)YesAny
@updatedAtYesYes (time::now())Yes (time::now())YesDate only
@createdAtYesYes (time::now())NoYesDate only
@nowNoN/A (computed)N/A (computed)NoDate only

On this page