Skip to content

Properties

Properties define the columns in your database table and how they are rendered in the admin UI. Each property has a type that determines:

  • The database column type (via Drizzle schema generation)
  • The form field component
  • The table cell renderer
  • The validation rules
TypeDescriptionPostgreSQL Column
stringText, select, markdown, file upload, URL, emailvarchar, text, jsonb
numberInteger, decimal, currencyinteger, numeric, bigint, serial
booleanTrue/false toggleboolean
dateDate, datetime, timestamptimestamp, date
arrayOrdered list of valuesjsonb
mapKey-value objectjsonb
geopointLatitude/longitude pairjsonb
referenceEmbedded reference to another entityvarchar (stores ID)
relationSQL foreign key relationUses the relations array

All property types share these options:

PropertyTypeDescription
typestringRequired. Data type (see above)
namestringRequired. Display label
descriptionstringHelp text shown below the field
defaultValueanyDefault value for new entities
validationobjectValidation rules
propertyConfigstringRegistered property config key
columnNamestringExplicit database column name (bypasses snake_case conversion)
callbacksPropertyCallbacksHooks for afterRead and beforeSave transforms
dynamicPropsfunctionDynamic property builder (see Conditional Fields)
conditionsPropertyConditionsDeclarative JSON Logic conditions

UI-related options are nested under the ui sub-object:

price: {
type: "number",
name: "Price",
ui: {
readOnly: true,
columnWidth: 120,
hideFromCollection: false
}
}
PropertyTypeDescription
ui.readOnlybooleanPrevent editing
ui.disabledboolean | PropertyDisabledConfigDisable with optional tooltip
ui.hideFromCollectionbooleanHide from table view
ui.columnWidthnumberColumn width in pixels (table view)
ui.widthPercentagenumberField width as a percentage in the form view
ui.FieldReact.ComponentTypeCustom field component
ui.PreviewReact.ComponentTypeCustom table cell component

The string type is the most versatile — depending on the options you set, it renders as different widgets.

A basic single-line text input.

name: {
type: "string",
name: "Name",
validation: { required: true, min: 2, max: 200 }
}

Set multiline: true to render as a textarea.

description: {
type: "string",
name: "Description",
multiline: true
}

Set markdown: true to render a full markdown editor with toolbar.

body: {
type: "string",
name: "Blog text",
markdown: true
}

Set email: true to add email format validation and render with an email icon.

email: {
type: "string",
name: "User email",
email: true,
validation: { required: true }
}

Set url: true to add URL format validation and render with a link icon.

website: {
type: "string",
name: "Amazon link",
url: true
}

Set storage to render a file upload dropzone.

avatar: {
type: "string",
name: "Main image",
storage: {
storagePath: "avatars",
acceptedFiles: ["image/*"],
maxSize: 2 * 1024 * 1024
}
}

Set enum to render a select dropdown. See the Enum Values section for details.

category: {
type: "string",
name: "Category",
enum: [
{ id: "electronics", label: "Electronics", color: "blueDark" },
{ id: "clothing", label: "Clothing", color: "pinkLight" },
]
}

Set enum + multiSelect: true to allow picking multiple values.

locales: {
type: "string",
name: "Available locales",
multiSelect: true,
enum: [
{ id: "es", label: "Spanish", color: "pinkLight" },
{ id: "en", label: "English", color: "blueLight" },
{ id: "fr", label: "French", color: "purpleLight" },
]
}
PropertyTypeDescription
multilinebooleanRender as textarea
markdownbooleanRender as markdown editor
emailbooleanEmail format validation
urlbooleanURL format validation
storageStorageConfigEnable file upload
enumEnumValuesRender as select dropdown
multiSelectbooleanAllow multiple enum selections
columnTypestringDatabase column: "varchar", "text"
isIdstringID generation: "uuid", "cuid", "increment", "manual"
userSelectbooleanRender as a user picker
previewAsTagbooleanRender this string as a tag in previews
clearablebooleanAdd an icon to clear the value (set to null)
price: {
type: "number",
name: "Price",
validation: { required: true, min: 0 }
}
quantity: {
type: "number",
name: "Quantity",
columnType: "integer" // Store as integer
}

Number fields render as a standard text input with numeric validation.

PropertyTypeDescription
enumEnumValuesRender as select with numeric values
columnTypestring"integer", "bigint", "numeric", "serial", "smallint"
isIdstringID generation strategy
clearablebooleanAdd an icon to clear the value (set to null)
active: {
type: "boolean",
name: "Selectable",
defaultValue: true
}

Booleans render as a toggle switch.

Set mode: "date" to show a date picker without time.

event_date: {
type: "date",
name: "Expiry date",
mode: "date"
}

The default mode "date_time" includes both date and time.

arrival_time: {
type: "date",
name: "Arrival time",
mode: "date_time"
}

Use autoValue to automatically set timestamps on create or update.

created_at: {
type: "date",
name: "Created At",
autoValue: "on_create",
ui: { readOnly: true }
}
updated_at: {
type: "date",
name: "Updated At",
autoValue: "on_update"
}
PropertyTypeDescription
mode"date" | "date_time"Date only or date + time (default: "date_time")
autoValue"on_create" | "on_update"Auto-set timestamps
columnTypestring"timestamp", "date"
timezonestringTimezone string to evaluate the date in
clearablebooleanAdd an icon to clear the value (set to null)

Use of to define a repeatable list of items.

tags: {
type: "array",
name: "Tags",
of: { type: "string" }
}

Combine of with storage for a multi-file upload.

images: {
type: "array",
name: "Images",
of: {
type: "string",
storage: { storagePath: "images", acceptedFiles: ["image/*"] }
}
}

Use oneOf to create a block editor with multiple content types. Each key creates a card type that users can pick from.

content: {
type: "array",
name: "Content",
oneOf: {
properties: {
text: {
type: "map",
properties: {
body: { type: "string", name: "Text", markdown: true }
}
},
image: {
type: "map",
properties: {
src: { type: "string", name: "Image", storage: { storagePath: "content" } },
caption: { type: "string", name: "Caption" }
}
}
}
}
}
PropertyTypeDescription
ofProperty | Property[]Property schema for array items
oneOfobjectArray of typed objects with multiple discriminator types
expandedbooleanShould the field be initially expanded (default: true)
minimalistViewbooleanDisplay child properties directly without extendable panel
sortablebooleanCan elements be reordered (default: true)
canAddElementsbooleanCan new elements be added (default: true)

Use properties to define a structured object with named fields.

address: {
type: "map",
name: "Address",
properties: {
street: { type: "string", name: "Street" },
zip: { type: "string", name: "Postal code" }
}
}

Set keyValue: true to render an arbitrary key-value pairs editor.

metadata: {
type: "map",
name: "Key value",
keyValue: true
}
PropertyTypeDescription
propertiesPropertiesRecord of properties included in the map
propertiesOrderstring[]Ordered keys for rendering
previewPropertiesstring[]Which properties to show in the table preview
spreadChildrenbooleanRender child properties as separate columns in table view
minimalistViewbooleanDisplay properties without a wrapping panel
expandedbooleanShould the field be initially expanded (default: true)
keyValuebooleanRender as arbitrary key-value pairs editor

References link to entities in another collection. They render as a preview card showing the referenced entity’s details.

client: {
type: "reference",
name: "Related client",
path: "clients",
previewProperties: ["first_name", "last_name", "email"]
}

Used with string or number properties to render selects:

// Simple array
enum: ["draft", "published", "archived"]
// With labels
enum: [
{ id: "draft", label: "Draft" },
{ id: "published", label: "Published" },
{ id: "archived", label: "Archived" }
]
// With colors (for Kanban columns and chips)
enum: [
{ id: "draft", label: "Draft", color: "grayDark" },
{ id: "published", label: "Published", color: "greenDark" },
{ id: "archived", label: "Archived", color: "orangeDark" }
]
validation: {
required: true, // Field is required
unique: true, // Must be unique in the table
requiredMessage: "Custom error message",
// String-specific
min: 2, // Minimum length
max: 200, // Maximum length
matches: /^[a-z]+$/, // Regex pattern
email: true, // Email format
url: true, // URL format
// Number-specific
min: 0, // Minimum value
max: 1000, // Maximum value
integer: true, // Must be integer
// Array-specific
min: 1, // Minimum items
max: 10, // Maximum items
}

You can make fields dynamic so they react to the entity’s values. There are two ways to do this:

You can use the conditions property to define declarative JSON Logic rules that can be serialized and modified visually in the collection editor.

price: {
type: "number",
name: "Price",
conditions: {
disabled: { "==": [{ "var": "values.is_free" }, true] },
required: { "!=": [{ "var": "values.is_free" }, true] },
min: 0,
clearOnDisabled: true // Set to null if field gets disabled
}
}

The conditions object gives you access to:

  • disabled, hidden, readOnly
  • required, min, max
  • defaultValue
  • enumConditions, allowedEnumValues, excludedEnumValues
  • referencePath, referenceFilter
  • canAddElements, sortable (for arrays)

For complex behavior that can’t be expressed via JSON Logic, you can use dynamicProps which evaluates a Javascript function.

price: {
type: "number",
name: "Price",
dynamicProps: ({ values, user }) => ({
disabled: values.is_free === true || !user.roles.includes("admin"),
validation: values.is_free ? {} : { required: true, min: 0 }
})
}