Field Type Gallery
Complete reference for every ObjectStack field type with per-type configuration properties
Field Type Gallery
ObjectStack provides a comprehensive set of field types covering every data modeling need — from basic text and numbers to AI vectors and rich media. This guide organizes them by category with per-type configuration details.
Source: packages/spec/src/data/field.zod.ts
Import: import { FieldType, FieldSchema } from '@objectstack/spec/data'
Text Types
text
Single-line plain text input.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
minLength | number | — | Minimum character length |
format | string | — | Validation format pattern |
{ name: 'first_name', label: 'First Name', type: 'text', maxLength: 100 }textarea
Multi-line text input for longer content.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
minLength | number | — | Minimum character length |
{ name: 'description', label: 'Description', type: 'textarea', maxLength: 5000 }email
Email address with built-in format validation.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
{ name: 'email', label: 'Email', type: 'email', required: true, unique: true }url
URL with format validation.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
{ name: 'website', label: 'Website', type: 'url' }phone
Phone number field.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
format | string | — | Phone format pattern |
{ name: 'phone', label: 'Phone', type: 'phone' }password
Masked password input (stored as a one-way hash, owned by the auth subsystem). For reversible encrypted-at-rest secrets (API keys, tokens), use the secret type instead.
{ name: 'password', label: 'Password', type: 'password', required: true }secret
Reversible, encrypted-at-rest value (DB password, API key, token). Unlike password (a one-way hash), a secret is encrypted on write via the registered crypto provider, stored as an opaque ref on the row, and masked on read. Fail-closed: with no provider configured, writes throw rather than persist cleartext.
{ name: 'api_key', label: 'API Key', type: 'secret' }Rich Content Types
markdown
Markdown-formatted text with preview support.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
{ name: 'readme', label: 'README', type: 'markdown' }html
Rich HTML content.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
{ name: 'body', label: 'Body', type: 'html' }richtext
WYSIWYG rich text editor content.
| Property | Type | Default | Description |
|---|---|---|---|
maxLength | number | — | Maximum character length |
{ name: 'content', label: 'Content', type: 'richtext' }Number Types
number
Numeric value with optional precision.
| Property | Type | Default | Description |
|---|---|---|---|
precision | number | — | Total digits |
scale | number | — | Decimal places |
min | number | — | Minimum value |
max | number | — | Maximum value |
{ name: 'quantity', label: 'Quantity', type: 'number', min: 0, max: 99999 }currency
Monetary value with currency configuration.
| Property | Type | Default | Description |
|---|---|---|---|
precision | number | — | Total digits |
scale | number | — | Decimal places |
min | number | — | Minimum value |
max | number | — | Maximum value |
currencyConfig.precision | number | 2 | Decimal precision for currency |
currencyConfig.currencyMode | 'dynamic' | 'fixed' | 'dynamic' | Whether currency is per-record or fixed |
currencyConfig.defaultCurrency | string | 'CNY' | Default currency code |
{ name: 'price', label: 'Price', type: 'currency', currencyConfig: { precision: 2, currencyMode: 'fixed', defaultCurrency: 'USD' } }percent
Percentage value (0–100 or decimal).
| Property | Type | Default | Description |
|---|---|---|---|
precision | number | — | Total digits |
scale | number | — | Decimal places |
min | number | — | Minimum value |
max | number | — | Maximum value |
{ name: 'discount', label: 'Discount', type: 'percent', min: 0, max: 100 }Date & Time Types
date
Date value (no time component).
{ name: 'birth_date', label: 'Birth Date', type: 'date' }datetime
Date and time value with timezone support.
{ name: 'created_at', label: 'Created At', type: 'datetime', readonly: true }time
Time-only value (no date component).
{ name: 'start_time', label: 'Start Time', type: 'time' }Boolean Types
boolean
Standard true/false field.
{ name: 'is_active', label: 'Active', type: 'boolean', defaultValue: true }toggle
Toggle switch (functionally identical to boolean, different UI).
{ name: 'notifications_enabled', label: 'Notifications', type: 'toggle' }Selection Types
select
Single-choice dropdown.
| Property | Type | Default | Description |
|---|---|---|---|
options | SelectOption[] | required | List of available options |
SelectOption properties:
| Property | Type | Required | Description |
|---|---|---|---|
label | string | ✅ | Display label |
value | string | ✅ | Machine value (snake_case) |
color | string | — | Badge color |
default | boolean | — | Pre-selected option |
{
name: 'status', label: 'Status', type: 'select',
options: [
{ label: 'Open', value: 'open', color: 'blue', default: true },
{ label: 'In Progress', value: 'in_progress', color: 'yellow' },
{ label: 'Done', value: 'done', color: 'green' }
]
}multiselect
Multi-choice dropdown. Same options property as select.
{
name: 'tags', label: 'Tags', type: 'multiselect',
options: [
{ label: 'Bug', value: 'bug' },
{ label: 'Feature', value: 'feature' },
{ label: 'Enhancement', value: 'enhancement' }
]
}radio
Radio button group (single choice). Same options property as select.
{
name: 'priority', label: 'Priority', type: 'radio',
options: [
{ label: 'Low', value: 'low' },
{ label: 'Medium', value: 'medium', default: true },
{ label: 'High', value: 'high' }
]
}checkboxes
Checkbox group (multi-choice). Same options property as select.
{
name: 'features', label: 'Features', type: 'checkboxes',
options: [
{ label: 'Email', value: 'email' },
{ label: 'SMS', value: 'sms' },
{ label: 'Push', value: 'push' }
]
}Relational Types
lookup
Reference to a record in another object (foreign key).
| Property | Type | Default | Description |
|---|---|---|---|
reference | string | required | Target object name (snake_case) |
referenceFilters | string[] | — | Legacy — accepted by the schema but not read by the record-picker (filters nothing). Use structured lookupFilters + dependsOn instead; see Relationships |
deleteBehavior | 'restrict' | 'cascade' | 'set_null' | 'set_null' | Behavior when referenced record is deleted (a required lookup left at the default set_null is escalated to restrict, since a NOT NULL foreign key cannot be cleared) |
{ name: 'company', label: 'Company', type: 'lookup', reference: 'account' }user
Person picker — a lookup specialized to the built-in sys_user object. Stored identically to lookup (foreign key to sys_user.id; multiple: true stores an array) and resolved through the same $expand machinery. Supports defaultValue: 'current_user' to stamp the acting user's id on insert.
Field.user({ label: 'Assignee' })
Field.user({ label: 'Watchers', multiple: true })
Field.user({ label: 'Owner', defaultValue: 'current_user' })master_detail
Parent-child relationship (cascading delete by default).
| Property | Type | Default | Description |
|---|---|---|---|
reference | string | required | Target (master) object name |
referenceFilters | string[] | — | Legacy — accepted by the schema but not read by the record-picker (filters nothing). Use structured lookupFilters + dependsOn instead; see Relationships |
deleteBehavior | 'restrict' | 'cascade' | 'set_null' | 'cascade' | Behavior when parent is deleted (master-detail cascades unless set to restrict) |
inlineEdit | boolean | 'grid' | 'form' | — | Edit child records inline on the parent create/edit form (true = auto-pick, 'grid', or 'form') |
inlineColumns | array | — | Optional explicit inline grid columns |
inlineAmountField | string | — | Numeric child field used for the inline running total |
{
name: 'order',
label: 'Order',
type: 'master_detail',
reference: 'order',
inlineEdit: true,
inlineAmountField: 'line_total',
}tree
Self-referential hierarchy (e.g., categories, org chart).
| Property | Type | Default | Description |
|---|---|---|---|
reference | string | required | Same object (self-reference) |
{ name: 'parent_category', label: 'Parent Category', type: 'tree', reference: 'category' }Media Types
All media types support the fileAttachmentConfig property:
| Property | Type | Description |
|---|---|---|
maxSize | number | Maximum file size in bytes |
minSize | number | Minimum file size in bytes |
allowedTypes | string[] | Allowed file extensions |
blockedTypes | string[] | Blocked file extensions |
allowedMimeTypes | string[] | Allowed MIME types |
blockedMimeTypes | string[] | Blocked MIME types |
virusScan | boolean | Enable virus scanning |
storageProvider | string | Storage provider name |
storageBucket | string | Storage bucket name |
allowMultiple | boolean | Allow multiple files |
versioningEnabled | boolean | Enable file versioning |
maxVersions | number | Maximum version count |
publicRead | boolean | Publicly accessible |
presignedUrlExpiry | number | URL expiry in seconds |
image
Image file with optional validation.
{
name: 'photo', label: 'Photo', type: 'image',
fileAttachmentConfig: { maxSize: 5242880, allowedMimeTypes: ['image/png', 'image/jpeg'] }
}file
Generic file attachment.
{
name: 'attachment', label: 'Attachment', type: 'file',
fileAttachmentConfig: { maxSize: 10485760, virusScan: true }
}avatar
Profile image (typically square, small).
{ name: 'avatar', label: 'Avatar', type: 'avatar' }video
Video file attachment.
{
name: 'demo_video', label: 'Demo Video', type: 'video',
fileAttachmentConfig: { maxSize: 104857600, allowedMimeTypes: ['video/mp4'] }
}audio
Audio file attachment.
{
name: 'recording', label: 'Recording', type: 'audio',
fileAttachmentConfig: { maxSize: 52428800 }
}Computed Types
formula
Calculated field using a CEL expression (see Expressions).
| Property | Type | Default | Description |
|---|---|---|---|
expression | string | Expression | required | CEL calculation expression |
returnType | 'number' | 'text' | 'boolean' | 'date' | — | Declared value type of the computed result |
dependencies | string[] | — | Fields the formula depends on |
{ name: 'total', label: 'Total', type: 'formula', expression: 'record.quantity * record.unit_price', returnType: 'number' }summary
Roll-up summary from child records.
| Property | Type | Default | Description |
|---|---|---|---|
summaryOperations.object | string | required | Child object to aggregate |
summaryOperations.field | string | required | Child field to aggregate; ignored for count |
summaryOperations.function | enum | required | count, sum, avg, min, or max |
summaryOperations.relationshipField | string | auto | Child FK back to the parent when it cannot be inferred |
{
name: 'task_count',
label: 'Task Count',
type: 'summary',
summaryOperations: {
object: 'task',
field: 'id',
function: 'count',
relationshipField: 'project',
},
}autonumber
Auto-incrementing number with format template.
| Property | Type | Default | Description |
|---|---|---|---|
autonumberFormat | string | — | Format template (e.g., 'INV-{0000}') |
{ name: 'ticket_number', label: 'Ticket #', type: 'autonumber', autonumberFormat: 'TKT-{0000}' }Embedded Structured Types
These types store structured values as JSON on the parent row — no separate table or foreign key.
composite
Single embedded sub-object with declared sub-fields (similar to a Strapi component / ACF group).
{ name: 'dimensions', label: 'Dimensions', type: 'composite' }repeater
Repeating embedded sub-object array with declared sub-fields (similar to a Strapi repeatable component / ACF repeater).
{ name: 'line_items', label: 'Line Items', type: 'repeater' }record
Name-keyed map of embedded sub-objects (Record<string, SubObject>). Insertion order is display order. Used for collections where each item has a stable machine name. See ADR-0007.
{ name: 'settings', label: 'Settings', type: 'record' }Enhanced Types
location
Geographic coordinates. Stored as { latitude, longitude, altitude?, accuracy? } (latitude −90..90, longitude −180..180). No per-type config properties.
{ name: 'headquarters', label: 'Location', type: 'location' }address
Structured postal address. Stored as { street, city, state, postalCode, country, countryCode, formatted } (all parts optional). No per-type config properties.
{ name: 'billing_address', label: 'Billing Address', type: 'address' }code
Source code with syntax highlighting.
| Property | Type | Default | Description |
|---|---|---|---|
language | string | — | Programming language for highlighting |
{ name: 'snippet', label: 'Code Snippet', type: 'code', language: 'typescript' }json
Raw JSON data.
{ name: 'metadata', label: 'Metadata', type: 'json' }color
Color picker. Stores the color value as a string. No per-type config properties.
{ name: 'brand_color', label: 'Brand Color', type: 'color' }rating
Star rating input.
| Property | Type | Default | Description |
|---|---|---|---|
max | number | 5 | Maximum rating value (set by the Field.rating(max) factory) |
{ name: 'satisfaction', label: 'Rating', type: 'rating', max: 5 }
// or with the factory:
// satisfaction: Field.rating(5, { label: 'Rating' })slider
Range slider input.
| Property | Type | Default | Description |
|---|---|---|---|
min | number | — | Minimum value |
max | number | — | Maximum value |
step | number | 1 | Step increment |
{ name: 'confidence', label: 'Confidence', type: 'slider', min: 0, max: 100, step: 5 }signature
Digital signature capture.
{ name: 'approval_signature', label: 'Signature', type: 'signature' }qrcode
QR/barcode value rendered as a scannable code. No per-type config properties.
{ name: 'asset_tag', label: 'Asset Tag', type: 'qrcode' }progress
Progress bar (0–100).
{ name: 'completion', label: 'Completion', type: 'progress' }tags
Tag input with autocomplete.
{ name: 'labels', label: 'Labels', type: 'tags' }AI / ML Types
vector
Vector embeddings for semantic search and similarity.
| Property | Type | Default | Description |
|---|---|---|---|
dimensions | number | required | Vector dimensionality (e.g., 1536 for OpenAI embeddings) |
The nested vectorConfig object (with distanceMetric, indexed, indexType, …) is retained for back-compat only and is a runtime no-op — set the flat dimensions property instead.
{ name: 'embedding', label: 'Embedding', type: 'vector', dimensions: 1536 }
// or with the factory:
// embedding: Field.vector(1536, { label: 'Embedding' })Universal Field Properties
These properties are available on all field types:
| Property | Type | Default | Description |
|---|---|---|---|
name | string | required | Machine name (snake_case) |
label | string | — | Human-readable display label |
description | string | — | Field description / help text |
type | FieldType | required | One of the supported field types |
required | boolean | false | Whether the field is required |
unique | boolean | false | Enforce uniqueness |
multiple | boolean | false | Allow array of values |
searchable | boolean | false | Include in search index |
sortable | boolean | true | Allow sorting by this field |
hidden | boolean | false | Hide from default views |
readonly | boolean | false | Prevent user edits |
index | boolean | false | Create database index |
externalId | boolean | false | External system identifier |
defaultValue | any | — | Default value for new records |
group | string | — | Field grouping / section |
inlineHelpText | string | — | Inline help tooltip |
trackHistory | boolean | — | Render this field's value changes as entries on the record activity timeline |
requiredPermissions | string[] | — | Capabilities required to read/edit this field (masked on read, denied on write) |
dependencies | string[] | — | Names of fields this field depends on (formulas, visibility rules, etc.) |
visibleWhen | Expression | — | Show field only when predicate is true |
readonlyWhen | Expression | — | Make field read-only when predicate is true |
requiredWhen | Expression | — | Require field when predicate is true |
conditionalRequired | Expression | — | Deprecated alias of requiredWhen |
Choosing a Field Type
Not sure which type fits your data? Follow the Field Type Decision Tree — a flowchart, quick-reference tables, and a use-case mapping for every type in this gallery.