Field Validation Rules
Default validation behavior, required properties, and constraints for each ObjectStack field type
Field Validation Rules
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:
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
name | string | — | Must match ^[a-z_][a-z0-9_]*$ (snake_case) |
label | string | — | Human-readable display name |
type | FieldType | — | Must be a member of the FieldType enum |
required | boolean | false | Rejects null/undefined at runtime when true |
unique | boolean | false | Enforces database-level uniqueness constraint |
multiple | boolean | false | Stores value as array (applicable for select, lookup, file, image) |
hidden | boolean | false | Excluded from default UI rendering |
readonly | boolean | false | Blocks user edits in UI forms; server-enforced on update — a non-system write to the field is silently dropped from the payload (insert exempt) |
sortable | boolean | true | Whether field appears in list view sort options |
index | boolean | false | Creates standard database index |
externalId | boolean | false | Marks field as external ID for upsert operations |
trackHistory | boolean | — | Render this field's value changes as entries on the record activity timeline |
visibleWhen | string | Expression | — | CEL predicate; field is shown only when TRUE |
readonlyWhen | string | Expression | — | CEL predicate; field is read-only when TRUE |
requiredWhen | string | Expression | — | CEL predicate; field is required when TRUE |
conditionalRequired | string | Expression | — | Deprecated alias of requiredWhen |
Text Types
text
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Rejects values exceeding character count |
minLength | number | — | Rejects values below character count |
format | string | — | Validates against format pattern (e.g., regex) |
Default constraints: None. Unbounded text unless maxLength is set.
textarea
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Rejects values exceeding character count |
minLength | number | — | Rejects values below character count |
Default constraints: None. Multi-line text with no length limit by default.
email
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
format | string | email | Validates 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
format | string | url | Validates URL format (protocol required) |
Default constraints: Must be a valid URL with protocol prefix.
phone
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
format | string | phone | Validates 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Maximum password length |
minLength | number | — | Minimum password length |
Default constraints: Validated the same as text (maxLength/minLength only) — the engine does not automatically hash or mask a password-typed field's value on read; even the platform's own credential column (sys_account.password) is declared as Field.text(), with hashing and verification owned entirely by the auth subsystem (better-auth), not driven by this field type. For a reversible encrypted-at-rest value on your own objects, use the secret type instead.
Rich Content Types
markdown
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Character limit on raw markdown source |
Default constraints: Accepts valid Markdown syntax. No length limit by default.
html
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Character limit on raw HTML source |
Default constraints: HTML content is sanitized to prevent XSS. No length limit by default.
richtext
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
maxLength | number | — | Character limit on serialized content |
Default constraints: Stored as structured rich text (e.g., ProseMirror/Tiptap JSON). Sanitized on save.
Number Types
number
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
min | number | — | Rejects values below minimum |
max | number | — | Rejects values above maximum |
precision | number | — | Total number of digits allowed |
scale | number | — | Number of decimal places |
Default constraints: Any valid number. No range or precision limits by default.
currency
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
min | number | — | Minimum monetary value |
max | number | — | Maximum monetary value |
currencyConfig.precision | number | 2 | Decimal places (0–10) |
currencyConfig.currencyMode | enum | dynamic | dynamic (user-selectable) or fixed (single currency) |
currencyConfig.defaultCurrency | string | CNY | 3-character currency code (ISO 4217 or crypto) |
Default constraints: Stored as { value, currency } pair. Precision defaults to 2 decimal places.
percent
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
min | number | — | Minimum percentage value |
max | number | — | Maximum percentage value |
precision | number | — | Total digits |
scale | number | — | Decimal 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
defaultValue | boolean | — | Initial value when field is empty |
Default constraints: Only accepts true or false. Renders as checkbox.
toggle
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
defaultValue | boolean | — | Initial value when field is empty |
Default constraints: Identical validation to boolean. Distinct UI — renders as toggle switch.
Selection Types
select
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
options | SelectOption[] | — | Required. Static option list |
defaultValue | string | — | Must 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
options | SelectOption[] | — | Required. Static option list |
Default constraints: Stores array of selected option values. Each value validated against options.
radio
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
options | SelectOption[] | — | Required. Static option list |
Default constraints: Single-value selection. Same validation as select with radio button UI.
checkboxes
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
options | SelectOption[] | — | Required. Static option list |
Default constraints: Multi-value selection. Same validation as multiselect with checkbox group UI.
Relational Types
lookup
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
reference | string | — | Required. Target object name |
referenceFilters | string[] | — | Legacy — schema-accepted but not read by the record-picker; use lookupFilters + dependsOn |
deleteBehavior | enum | set_null | set_null, cascade, or restrict |
multiple | boolean | false | Allow multiple references |
Default constraints: Validates that referenced record exists. Foreign key integrity enforced.
master_detail
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
reference | string | — | Required. Parent object name |
deleteBehavior | enum | cascade | Master-detail cascades at runtime unless set to restrict |
Default constraints: Enforces parent-child ownership. Child records cascade-delete with the parent by default.
tree
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
reference | string | — | Required. 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
fileAttachmentConfig | object | — | File size, type, and image dimension rules |
multiple | boolean | false | Allow multiple image uploads |
Default constraints: Accepts common image MIME types. Optional dimension and thumbnail validation via fileAttachmentConfig.
file
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
fileAttachmentConfig | object | — | Full file upload validation config |
multiple | boolean | false | Allow multiple file uploads |
Default constraints: Accepts any file type unless restricted. Supports virus scanning, size limits, and type restrictions.
// File field with validation
{
name: 'contract_pdf',
label: 'Contract',
type: 'file',
fileAttachmentConfig: {
maxSize: 10485760, // 10MB
allowedTypes: ['.pdf', '.docx'],
virusScan: true,
virusScanProvider: 'clamav'
}
}avatar
Default constraints: Single image upload. Typically constrained to square aspect ratio and small file sizes.
video
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
fileAttachmentConfig | object | — | File size and type restrictions |
Default constraints: Accepts common video MIME types. Size limits recommended via fileAttachmentConfig.
audio
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
fileAttachmentConfig | object | — | File size and type restrictions |
Default constraints: Accepts common audio MIME types. Size limits recommended via fileAttachmentConfig.
Computed & System Types
formula
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
expression | string | — | Required. Formula expression |
dependencies | string[] | — | Fields this formula depends on |
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',
dependencies: ['first_name', 'last_name']
}summary
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
summaryOperations | object | — | Required. Roll-up definition |
summaryOperations.object | string | — | Child object to aggregate |
summaryOperations.field | string | — | Field to aggregate |
summaryOperations.function | enum | — | count, sum, min, max, or avg |
Default constraints: Read-only. Value computed from child records. Only valid on master objects.
autonumber
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
autonumberFormat | string | — | Display format pattern (e.g., CASE-{0000}) |
Default constraints: Read-only. Auto-incremented. Cannot be manually set after creation.
Enhanced Types
location
Default constraints: Stored as { latitude, longitude, altitude?, accuracy? }. Latitude: -90 to 90. Longitude: -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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
language | string | — | Programming 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
max | number | 5 | Maximum rating value (set by the Field.rating(max) factory) |
Default constraints: Integer between 0 and max.
slider
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
min | number | — | Minimum slider value |
max | number | — | Maximum slider value |
step | number | 1 | Step 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
min | number | — | Minimum value (typically 0) |
max | number | — | Maximum 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
| Property | Type | Default | Validation Behavior |
|---|---|---|---|
dimensions | number | — | Required. Vector size (1–10,000) |
Default constraints: Must be a numeric array of exactly dimensions length. The nested vectorConfig object is retained for back-compat only and is a runtime no-op — set the flat dimensions property instead.
{
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:
| Property | Type | Default | Description |
|---|---|---|---|
requiredPermissions | string[] | — | Capabilities required to read/edit the field — masked on read, denied on write unless the caller holds all of them (ADR-0066 D3) |
trackHistory | boolean | — | Render 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 masking/encryption code path.
password is validated like plain text and has no built-in hashing or read-masking
(see the password section above). See the
Field Type Gallery.
Quick Validation Summary
| Field Type | Required Props | Key Constraints |
|---|---|---|
text | — | maxLength, minLength, format |
textarea | — | maxLength, minLength |
email | — | Basic local@domain shape (not full RFC 5322) |
url | — | Valid URL with protocol |
phone | — | Permissive character set, not strict E.164 |
password | — | Validated like text; no built-in hashing/masking |
markdown | — | maxLength |
html | — | Sanitized, maxLength |
richtext | — | Sanitized, maxLength |
number | — | min, max, precision, scale |
currency | — | currencyConfig (precision, mode, code) |
percent | — | min, max, stored as decimal |
date | — | ISO 8601 date |
datetime | — | ISO 8601 datetime, UTC |
time | — | ISO 8601 time, 24h |
boolean | — | true / false only |
toggle | — | true / false only |
select | options | Option values must be lowercase system identifiers |
multiselect | options | Array of valid option values |
radio | options | Single value from options |
checkboxes | options | Array of valid option values |
lookup | reference | Foreign key integrity |
master_detail | reference | Cascade delete, ownership |
tree | reference | Self-referencing; no automatic cycle check |
image | — | fileAttachmentConfig for dimensions |
file | — | fileAttachmentConfig for restrictions |
avatar | — | Single image, typically square |
video | — | fileAttachmentConfig for size limits |
audio | — | fileAttachmentConfig for size limits |
formula | expression | Read-only, computed at runtime |
summary | summaryOperations | Read-only, roll-up from children |
autonumber | — | Read-only, auto-incremented |
location | — | Lat: -90–90, Lng: -180–180 |
address | — | Structured object (street, city, …) |
code | — | Plain text, language for highlighting |
json | — | Must be valid JSON |
color | — | Stored as a string |
rating | — | 0 to max (default 5) |
slider | — | min to max in step increments |
signature | — | Base64 image, typically immutable |
qrcode | — | Format-specific validation |
progress | — | Numeric, typically 0–100 |
tags | — | String array; no automatic trim/dedup |
vector | dimensions | Numeric array of exact dimensions length |