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
columnWidthnumberColumn width in pixels (table view)
readOnlybooleanPrevent editing
disabledboolean | PropertyDisabledConfigDisable with optional tooltip
hideFromCollectionbooleanHide from table view
defaultValueanyDefault value for new entities
validationobjectValidation rules
FieldReact.ComponentTypeCustom field component
PreviewReact.ComponentTypeCustom table cell component
propertyConfigstringRegistered property config key
editablebooleanEnable inline editing in table (default: true)
name: {
type: "string",
name: "Name",
validation: { required: true, min: 2, max: 200 }
}
description: {
type: "string",
name: "Description",
multiline: true, // Textarea
markdown: true // Markdown editor
}
category: {
type: "string",
name: "Category",
enum: [
{ id: "electronics", label: "Electronics", color: "blueDark" },
{ id: "clothing", label: "Clothing", color: "pinkLight" },
]
}
email: {
type: "string",
name: "Email",
email: true, // Email validation
validation: { required: true }
}
website: {
type: "string",
name: "Website",
url: true // URL validation
}
avatar: {
type: "string",
name: "Avatar",
storage: { // File upload
storagePath: "avatars",
acceptedFiles: ["image/*"],
maxSize: 2 * 1024 * 1024
}
}
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
}
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: "Active",
defaultValue: true
}

Switch field

created_at: {
type: "date",
name: "Created At",
autoValue: "on_create", // Set automatically on creation
readOnly: true
}
updated_at: {
type: "date",
name: "Updated At",
autoValue: "on_update" // Set automatically on every save
}
event_date: {
type: "date",
name: "Event Date",
mode: "date" // Date only (no time)
}

Date field

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)
tags: {
type: "array",
name: "Tags",
of: { type: "string" } // Array of strings
}
images: {
type: "array",
name: "Images",
of: {
type: "string",
storage: { storagePath: "images", acceptedFiles: ["image/*"] }
}
}
// Block editor (multiple types)
content: {
type: "array",
name: "Content Blocks",
oneOf: {
properties: {
text: {
type: "map",
properties: {
body: { type: "string", name: "Body", markdown: true }
}
},
image: {
type: "map",
properties: {
src: { type: "string", name: "Image", storage: { ... } },
caption: { type: "string", name: "Caption" }
}
}
}
}
}

Block field

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)
address: {
type: "map",
name: "Address",
properties: {
street: { type: "string", name: "Street" },
city: { type: "string", name: "City" },
zip: { type: "string", name: "ZIP Code" },
country: { type: "string", name: "Country" }
}
}
metadata: {
type: "map",
name: "Metadata",
keyValue: true // Free-form key-value editor
}

Group field

PropertyTypeDescription
propertiesPropertiesRecord of properties included in the map
propertiesOrderstring[]Ordered keys for rendering
previewPropertiesstring[]Which properties to show in the table preview
pickOnlySomeKeysbooleanLet the user selectively add keys in the UI
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

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" }
]

Select field

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 }
})
}