Field methods
Every s.* field is chainable. This page is the complete list of methods. For how the $-clauses render, see from schema to DDL.
Two kinds of method: app-side and DDL
The methods split by prefix, and the prefix tells you which side a method acts on:
- Non-
$methods are native Zod.s.*is a drop-in forz.*, so these behave exactly as in Zod — they shape the app-side value and its validation. $-prefixed methods are Schemic’s. They attach a SurrealQL clause to theDEFINE FIELD— the database side.
The two do not bridge; each side is explicit. Where Zod and SurrealDB have a similar concept, there are two distinct methods:
App-side (native Zod, non-$) | Database-side ($-prefixed) |
|---|---|
.readonly() — TS-immutable output | .$readonly() — SurrealDB READONLY |
.describe() / .meta() — Zod metadata | .$comment() — DDL COMMENT |
.refine() / .check() — app-side validation | .$assert() — DDL ASSERT |
Native Zod methods
These delegate to the underlying Zod schema and act on the app side. They are available on any s.* field:
refine, superRefine, check, overwrite, transform, pipe, brand, readonly, describe, meta, plus optional, nullable, nullish, array, default, prefault, catch, loose, strict.
Two combinators build composite types:
| Method | Result | DDL TYPE |
|---|---|---|
.or(other) | union | a | b |
.and(other) | intersection | merged object |
Modifiers
These shape the field’s type. They carry through to both the TypeScript type and the DDL.
| Method | DDL effect | Description |
|---|---|---|
.optional() | option<T> | The field may be absent. |
.nullable() | T | null | The field may be null. |
.array() | array<T> | A list of the field’s type. |
.loose() | FLEXIBLE | On an object field, allow arbitrary extra keys. |
SurrealQL clauses
Each $-method adds one clause to the field’s DEFINE FIELD. Expressions are written with the surql tag; $value refers to the field’s value.
| Method | DDL clause | Description |
|---|---|---|
.$default(expr) | DEFAULT expr | Value applied on insert when the field is absent. Makes the field optional in the create shape. |
.$defaultAlways() | DEFAULT ALWAYS | Reapply the default on update as well as insert. |
.$value(expr) | VALUE expr | Always compute the stored value from the expression, overriding input. |
.$computed(expr) | COMPUTED expr | A computed (read-only, derived) field. |
.$assert(expr) | ASSERT expr | A constraint SurrealDB enforces on write. |
.$readonly() | READONLY | Allowed on create, rejected on later change. |
.$comment(text) | COMMENT "text" | Attach a comment to the field. |
.$permissions(spec) | PERMISSIONS FOR ... WHERE ... | Per-operation access control (select, create, update). |
Constraint helpers
These translate Zod-style constraints into SurrealQL ASSERT clauses.
| Method | Applies to | Asserts |
|---|---|---|
.$min(n) / .$max(n) | numbers | lower / upper bound |
.$gt(n) / .$gte(n) / .$lt(n) / .$lte(n) | numbers | strict / inclusive comparison |
.$length(n) | strings, arrays | exact length |
.$regex(re) | strings | pattern match |
Indexing
| Method | DDL | Description |
|---|---|---|
.index() | DEFINE INDEX ... FIELDS <field> | A single-field index. |
.unique() | DEFINE INDEX ... UNIQUE | A single-field unique index. |
For composite indexes, use the table-level .index(name, fields, opts) — see definers.
Escape hatches
| Method | Description |
|---|---|
.$surreal(type, codec) | Set an explicit wire type and a custom { encode, decode } codec. See writing a custom codec. |
.$internal() | Mark the field internal: it exists on the table (so schemafull writes succeed) but grants no record-user access (PERMISSIONS NONE). |
Where to go next
- Schema builders — the field types these chain onto.
- Constraints, defaults & permissions — the how-to.
- Codecs — custom codecs via
.$surreal.