ObjectStackObjectStack

Field Validation Rules

Default validation behavior, required properties, and constraints for each ObjectStack field type

Every ObjectStack field type has built-in validation behavior that runs automatically at the schema level. This reference documents the default constraints, required properties, and validation semantics for each field type.

Source: packages/spec/src/data/field.zod.ts
Import: import { FieldSchema, FieldType } from '@objectstack/spec/data'


Universal Field Constraints

These properties apply to all field types and are validated by the base FieldSchema:

PropertyTypeDefaultValidation Behavior
namestringMust match ^[a-z_][a-z0-9_]*$ (snake_case)
labelstringHuman-readable display name
typeFieldTypeMust be a member of the FieldType enum
requiredbooleanfalseRejects null/undefined at runtime when true
uniquebooleanfalseEnforces database-level uniqueness constraint
multiplebooleanfalseStores value as array (applicable for select, lookup, file, image)
hiddenbooleanfalseExcluded from default UI rendering
readonlybooleanfalseBlocks user edits in UI forms; server-enforced on both create and update — a non-system write to the field is silently dropped from the payload (system-context writes such as import/seed/migration are exempt)
sortablebooleantrueWhether field appears in list view sort options
externalIdbooleanfalseMarks field as external ID for upsert operations
trackHistorybooleanRender this field's value changes as entries on the record activity timeline
visibleWhenstring | ExpressionCEL predicate; field is shown only when TRUE
readonlyWhenstring | ExpressionCEL predicate; field is read-only when TRUE
requiredWhenstring | ExpressionCEL predicate; field is required when TRUE

Text Types

text

PropertyTypeDefaultValidation Behavior
maxLengthnumberRejects values exceeding character count
minLengthnumberRejects values below character count
formatstringValidates against format pattern (e.g., regex)

Default constraints: None. Unbounded text unless maxLength is set.

textarea

PropertyTypeDefaultValidation Behavior
maxLengthnumberRejects values exceeding character count
minLengthnumberRejects values below character count

Default constraints: None. Multi-line text with no length limit by default.

email

PropertyTypeDefaultValidation Behavior
formatstringemailValidates a basic local@domain shape

Default constraints: Must contain an @ and a domain with a dot — a lightweight pattern check, not full RFC 5322 validation.

url

PropertyTypeDefaultValidation Behavior
formatstringurlValidates URL format (protocol required)

Default constraints: Must be a valid URL with protocol prefix.

phone

PropertyTypeDefaultValidation Behavior
formatstringphoneValidates a permissive phone-number character set

Default constraints: Accepts digits, + ( ) - . and spaces (minimum 5 characters) — a lenient character-set check, not strict E.164 structural validation.

password

PropertyTypeDefaultValidation Behavior
maxLengthnumberMaximum password length
minLengthnumberMinimum password length

Default constraints: Validated the same as text (maxLength/minLength only). On a generic (non-better-auth) object a password-typed value is stored plaintext at rest but masked to •••••••• on read through the normal query path (ADR-0100) — the engine does not hash or encrypt it. One-way hashing and verification of real login credentials are owned entirely by the auth subsystem (better-auth); its own credential column (sys_account.password) is a hashed Field.text() column that is exempt from this masking. For a reversible, encrypted-at-rest value on your own objects, use the secret type instead.

secret

PropertyTypeDefaultValidation Behavior
maxLengthnumberMaximum length of the cleartext value
minLengthnumberMinimum length of the cleartext value

Default constraints: Reversible, encrypted-at-rest value (DB password, API key, token) — ADR-0100. Fail-closed: with no ICryptoProvider registered, a write throws rather than persisting cleartext. The value is encrypted on write into a sys_secret row, only an opaque handle is persisted on the record, and reads are masked. Distinct from password, which is plaintext at rest (or one-way hashed inside the auth subsystem).


Rich Content Types

markdown

PropertyTypeDefaultValidation Behavior
maxLengthnumberCharacter limit on raw markdown source

Default constraints: Accepts valid Markdown syntax. No length limit by default.

html

PropertyTypeDefaultValidation Behavior
maxLengthnumberCharacter limit on raw HTML source

Default constraints: HTML content is sanitized to prevent XSS. No length limit by default.

richtext

PropertyTypeDefaultValidation Behavior
maxLengthnumberCharacter limit on serialized content

Default constraints: Stored as structured rich text (e.g., ProseMirror/Tiptap JSON). Sanitized on save.


Number Types

number

PropertyTypeDefaultValidation Behavior
minnumberRejects values below minimum
maxnumberRejects values above maximum
precisionnumberTotal number of digits allowed
scalenumberNumber of decimal places

Default constraints: Any valid number. No range or precision limits by default.

currency

PropertyTypeDefaultValidation Behavior
minnumberMinimum monetary value
maxnumberMaximum monetary value
currencyConfig.precisionnumber2Decimal places (0–10)
currencyConfig.currencyModeenumdynamicdynamic (user-selectable) or fixed (single currency)
currencyConfig.defaultCurrencystringCNY3-character currency code (ISO 4217 or crypto)

Default constraints: Stored as a bare number (a finite numeric scalar — valueSchemaFor routes currency to z.number().finite()); there is no { value, currency } envelope on the value path. The per-record currency code is a separate concern, carried by currencyConfig above. Precision defaults to 2 decimal places.

percent

PropertyTypeDefaultValidation Behavior
minnumberMinimum percentage value
maxnumberMaximum percentage value
precisionnumberTotal digits
scalenumberDecimal places

Default constraints: Stored as decimal (e.g., 0.85 for 85%). No range limit by default.


Date & Time Types

date

Required props: None.
Default constraints: Validates ISO 8601 date format (YYYY-MM-DD). No range restrictions.

datetime

Required props: None.
Default constraints: Validates ISO 8601 datetime format (YYYY-MM-DDTHH:mm:ssZ). Stored in UTC.

time

Required props: None.
Default constraints: Validates ISO 8601 time format (HH:mm:ss). 24-hour format.


Boolean Types

boolean

PropertyTypeDefaultValidation Behavior
defaultValuebooleanInitial value when field is empty

Default constraints: Only accepts true or false. Renders as checkbox.

toggle

PropertyTypeDefaultValidation Behavior
defaultValuebooleanInitial value when field is empty

Default constraints: Identical validation to boolean. Distinct UI — renders as toggle switch.


Selection Types

select

PropertyTypeDefaultValidation Behavior
optionsSelectOption[]Required. Static option list
defaultValuestringMust match an option value

Option validation: Each option value must be a lowercase system identifier — starts with a letter, then letters/digits/underscores/dots (^[a-z][a-z0-9_.]*$), minimum 2 characters.

multiselect

PropertyTypeDefaultValidation Behavior
optionsSelectOption[]Required. Static option list

Default constraints: Stores array of selected option values. Each value validated against options.

radio

PropertyTypeDefaultValidation Behavior
optionsSelectOption[]Required. Static option list

Default constraints: Single-value selection. Same validation as select with radio button UI.

checkboxes

PropertyTypeDefaultValidation Behavior
optionsSelectOption[]Required. Static option list

Default constraints: Multi-value selection. Same validation as multiselect with checkbox group UI.


Relational Types

lookup

PropertyTypeDefaultValidation Behavior
referencestringRequired. Target object name
referenceFiltersstring[]Removed (#2377, ADR-0049) — no longer part of the Field schema; use lookupFilters + dependsOn instead
deleteBehaviorenumset_nullset_null, cascade, or restrict
multiplebooleanfalseAllow multiple references; the value is validated as an array of ids

Default constraints: Validates that referenced record exists. Foreign key integrity enforced.

Multi-value lookups (multiple: true). The empty set is representable: an emptied multi-value lookup is stored and read back as [], never null — including when deleteBehavior: 'set_null' removes the last remaining member. The declared contract lives in the multiple and required doc blocks of packages/spec/src/data/field.zod.ts (rendered in the Field reference), and it makes required on a multi-value lookup mean non-empty array.

The required-means-non-empty half is enforced by the record validator (#9476, per the #9447 ruling): an explicit [] is rejected on insert, and on any update that supplies the field — exactly as null and "" are on a single-value required field. An update that omits the field never fails this check, so legacy rows stay editable. No application-level emptiness check is needed.

user

PropertyTypeDefaultValidation Behavior
multiplebooleanfalsetrue stores a JSON array of user ids
defaultValue'current_user'Stamps the acting user's id on insert

Default constraints: Person picker — a lookup specialized to the built-in sys_user object, so reference is implied and must not be authored. Stored as a foreign key to sys_user.id and resolved through the same $expand machinery as lookup; with multiple: true the stored value is a JSON array of ids.

master_detail

PropertyTypeDefaultValidation Behavior
referencestringRequired. Parent object name
deleteBehaviorenumcascadeMaster-detail cascades at runtime unless set to restrict

Default constraints: Enforces parent-child ownership. Child records cascade-delete with the parent by default.

tree

PropertyTypeDefaultValidation Behavior
referencestringRequired. Self-referencing object name

Default constraints: Self-referencing lookup for hierarchical structures. Stored and expanded like a lookup; the engine does not run a cycle check on write, so a self-reference chain that loops back on itself is not automatically rejected.


Media Types

image

PropertyTypeDefaultValidation Behavior
multiplebooleanfalseAllow multiple image uploads

Default constraints: Accepts common image MIME types. The schema has no field-level attachment-config property — fileAttachmentConfig was removed in the 16.x line (#2377).

file

PropertyTypeDefaultValidation Behavior
multiplebooleanfalseAllow multiple file uploads

Default constraints: Accepts any file type. The Field schema exposes no field-level upload-validation config — fileAttachmentConfig (and its maxSize / allowedTypes / virus-scan sub-keys) was removed in the 16.x line (#2377). File-storage constraints such as virus scanning are configured on the file-storage integration, not on the field.

// File field
{
  name: 'contract_pdf',
  label: 'Contract',
  type: 'file',
  multiple: false
}

avatar

Default constraints: Single image upload. Typically constrained to square aspect ratio and small file sizes.

video

Default constraints: Accepts common video MIME types. The field type has no per-field size/type config property in the schema.

audio

Default constraints: Accepts common audio MIME types. The field type has no per-field size/type config property in the schema.


Computed & System Types

formula

PropertyTypeDefaultValidation Behavior
expressionstringRequired. CEL formula expression
returnTypeenumOptional inferred result type: number, text, boolean, or date

Default constraints: Read-only. Value computed at runtime from expression. Not directly writable.

{
  name: 'full_name',
  label: 'Full Name',
  type: 'formula',
  expression: 'record.first_name + " " + record.last_name'
}

summary

PropertyTypeDefaultValidation Behavior
summaryOperationsobjectRequired. Roll-up definition
summaryOperations.objectstringChild object to aggregate
summaryOperations.fieldstringField to aggregate
summaryOperations.functionenumcount, sum, min, max, or avg

Default constraints: Read-only. Value computed from child records. Only valid on master objects.

autonumber

PropertyTypeDefaultValidation Behavior
autonumberFormatstringDisplay format pattern (e.g., CASE-{0000})

Default constraints: Read-only. Auto-incremented. Cannot be manually set after creation.


Embedded Structured Types

These types store structured values as JSON on the parent row — no separate table and no foreign key. Sub-field shapes are declared on the field, and the stored value is validated as an open object map (valueSchemaFor), so sub-keys are not constrained by the field type itself.

composite

Default constraints: Single embedded sub-object. Stored as a JSON object map (Record<string, unknown>). No per-type config properties.

repeater

Default constraints: Repeating embedded sub-object array. Stored as a JSON array of object maps (Array<Record<string, unknown>>); a non-array value is rejected. No per-type config properties.

record

Default constraints: Name-keyed map of embedded sub-objects (Record<string, SubObject>) — ADR-0007. Stored as a JSON object map; insertion order is display order. No per-type config properties.


Enhanced Types

location

Default constraints: Stored as { lat, lng, altitude?, accuracy? } — the keys are lat/lng, not latitude/longitude (LocationValueSchema, ADR-0104 D1). lat: -90 to 90. lng: -180 to 180. No per-type config properties.

address

Default constraints: Stored as structured object with street, city, state, postalCode, country, countryCode, formatted (all parts optional). No per-type config properties.

code

PropertyTypeDefaultValidation Behavior
languagestringProgramming language for syntax highlighting

Default constraints: Stored as plain text. Language used for UI syntax highlighting only.

json

Default constraints: Must be valid JSON. Parsed and validated on save.

color

Default constraints: Stores the color value as a string. No per-type config properties.

rating

PropertyTypeDefaultValidation Behavior
maxnumber5Maximum rating value (set by the Field.rating(max) factory)

Default constraints: Integer between 0 and max.

slider

PropertyTypeDefaultValidation Behavior
minnumberMinimum slider value
maxnumberMaximum slider value
stepnumber1Step increment

Default constraints: Numeric value between min and max in step increments.

signature

Default constraints: Stored as base64-encoded image data. Immutable after creation in most workflows.

qrcode

Default constraints: Stores the encoded value; rendered as a scannable code. No per-type config properties.

progress

PropertyTypeDefaultValidation Behavior
minnumberMinimum value (typically 0)
maxnumberMaximum value (typically 100)

Default constraints: Numeric value rendered as a progress bar. Usually 0–100.

tags

Default constraints: Stored as array of strings. A lone scalar value is coerced into a single-element array; the engine does not trim or deduplicate entries.


AI/ML Types

vector

PropertyTypeDefaultValidation Behavior
dimensionsnumberRequired. Vector size (1–10,000)

Default constraints: Must be a numeric array of exactly dimensions length. Set the flat dimensions property directly — the legacy nested vectorConfig object was removed in the 16.x line (#2377) and is no longer part of the schema.

{
  name: 'content_embedding',
  label: 'Content Embedding',
  type: 'vector',
  dimensions: 1536
}

Security & Compliance Properties

For sensitive data, use the properties and types the platform actually enforces:

PropertyTypeDefaultDescription
requiredPermissionsstring[]Capabilities required to read/edit the field — masked on read, denied on write unless the caller holds all of them (ADR-0066 D3)
trackHistorybooleanRender the field's value changes as entries on the record activity timeline

For reversible encrypted-at-rest values (API keys, tokens, DB passwords), use the secret field type — it is the type with an enforced encryption/masking code path (encrypted at rest via sys_secret, masked on read). password is validated like plain text and stored plaintext at rest with no built-in hashing or encryption; it is masked to •••••••• on read but offers no at-rest protection (see the password section above). See the Field Type Gallery.


Quick Validation Summary

Field TypeRequired PropsKey Constraints
textmaxLength, minLength, format
textareamaxLength, minLength
emailBasic local@domain shape (not full RFC 5322)
urlValid URL with protocol
phonePermissive character set, not strict E.164
passwordValidated like text; masked on read but plaintext at rest (no hashing/encryption)
secretEncrypted at rest via sys_secret, masked on read; fail-closed — writes throw with no ICryptoProvider
markdownmaxLength
htmlSanitized, maxLength
richtextSanitized, maxLength
numbermin, max, precision, scale
currencycurrencyConfig (precision, mode, code)
percentmin, max, stored as decimal
dateISO 8601 date
datetimeISO 8601 datetime, UTC
timeISO 8601 time, 24h
booleantrue / false only
toggletrue / false only
selectoptionsOption values must be lowercase system identifiers
multiselectoptionsArray of valid option values
radiooptionsSingle value from options
checkboxesoptionsArray of valid option values
lookupreferenceForeign key integrity
userLookup specialized to sys_user; multiple: true stores an id array
master_detailreferenceCascade delete, ownership
treereferenceSelf-referencing; no automatic cycle check
imageCommon image MIME types; multiple for many
fileAny file type; multiple for many (no field-level upload config)
avatarSingle image, typically square
videoCommon video MIME types
audioCommon audio MIME types
formulaexpressionRead-only, computed at runtime
summarysummaryOperationsRead-only, roll-up from children
autonumberRead-only, auto-incremented
compositeSingle embedded sub-object; stored as a JSON object map
repeaterEmbedded sub-object array; stored as a JSON array of object maps
recordName-keyed map of embedded sub-objects (ADR-0007)
locationLat: -90–90, Lng: -180–180
addressStructured object (street, city, …)
codePlain text, language for highlighting
jsonMust be valid JSON
colorStored as a string
rating0 to max (default 5)
slidermin to max in step increments
signatureBase64 image, typically immutable
qrcodeFormat-specific validation
progressNumeric, typically 0–100
tagsString array; no automatic trim/dedup
vectordimensionsNumeric array of exact dimensions length

On this page