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
Type Description PostgreSQL Column
string Text, select, markdown, file upload, URL, email varchar, text, jsonb
number Integer, decimal, currency integer, numeric, bigint, serial
boolean True/false toggle boolean
date Date, datetime, timestamp timestamp, date
array Ordered list of values jsonb
map Key-value object jsonb
geopoint Latitude/longitude pair jsonb
reference Embedded reference to another entity varchar (stores ID)
relation SQL foreign key relation Uses the relations array
vector Embedding, for nearest-neighbour search VECTOR(n) (pgvector)
binary Raw bytes, read and written as base64 bytea

All property types share these options:

Property Type Description
type string Required. Data type (see above)
name string Required. Display label
description string Help text shown below the field
defaultValue any Default value for new entities
validation object Validation rules
propertyConfig string Registered property config key
columnName string Explicit database column name (bypasses snake_case conversion)
callbacks PropertyCallbacks Hooks for afterRead and beforeSave transforms
dynamicProps function Dynamic property builder (see Conditional Fields)
conditions PropertyConditions Declarative JSON Logic conditions

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

price: {
type: "number",
name: "Price",
admin: {
readOnly: true,
columnWidth: 120,
hideFromCollection: false
}
}
Property Type Description
admin.readOnly boolean Prevent editing
admin.disabled boolean | PropertyDisabledConfig Disable with optional tooltip
admin.hideFromCollection boolean Hide from table view
admin.columnWidth number Column width in pixels (table view)
admin.span 1 | 2 | 3 | 4 Field width over the four-column form grid
admin.Field React.ComponentType Custom field component
admin.Preview React.ComponentType Custom 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: "pink" },
]
}

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

locales: {
type: "string",
name: "Available locales",
multiSelect: true,
enum: [
{ id: "es", label: "Spanish", color: "pink" },
{ id: "en", label: "English", color: "blueLight" },
{ id: "fr", label: "French", color: "purpleLight" },
]
}
Property Type Description
admin.multiline boolean Render as textarea
admin.markdown boolean Render as markdown editor
email boolean Email format validation
url boolean URL format validation
storage StorageConfig Enable file upload
enum EnumValues Render as select dropdown
multiSelect boolean Allow multiple enum selections
columnType string Database column: "varchar", "text"
isId string ID generation: "uuid", "cuid", "increment", "manual"
userSelect boolean Render as a user picker
admin.previewAsTag boolean Render this string as a tag in previews
admin.clearable boolean Add 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.

Property Type Description
enum EnumValues Render as select with numeric values
columnType string "integer", "bigint", "numeric", "serial", "smallint"
isId string ID generation strategy
admin.clearable boolean Add 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.

createdAt: {
type: "date",
name: "Created At",
autoValue: "on_create",
admin: { readOnly: true }
}
updatedAt: {
type: "date",
name: "Updated At",
autoValue: "on_update"
}
Property Type Description
mode "date" | "date_time" Date only or date + time (default: "date_time")
autoValue "on_create" | "on_update" Auto-set timestamps
columnType string "timestamp", "date"
timezone string Timezone string to evaluate the date in
admin.clearable boolean Add 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" }
}
}
}
}
}
Property Type Description
of Property | Property[] Property schema for array items
oneOf object Array of typed objects with multiple discriminator types
admin.expanded boolean Should the field be initially expanded (default: true)
admin.minimalistView boolean Display child properties directly without extendable panel
admin.sortable boolean Can elements be reordered (default: true)
admin.canAddElements boolean Can 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
}
Property Type Description
properties Properties Record of properties included in the map
propertiesOrder string[] Ordered keys for rendering
admin.previewProperties string[] Which properties to show in the table preview
admin.spreadChildren boolean Render child properties as separate columns in table view
admin.minimalistView boolean Display properties without a wrapping panel
admin.expanded boolean Should the field be initially expanded (default: true)
keyValue boolean Render 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",
admin: {
previewProperties: ["first_name", "last_name", "email"]
}
}

These apply to both reference and relation properties.

Property Type Description
admin.fixedFilter FilterValues Filter the entities offered in the selection widget
admin.widget "select" | "dialog" Which widget selects the related entity (relations only)
admin.includeId boolean Show the related entity’s id in previews (default: true)
admin.includeEntityLink boolean Show a link that opens the related entity (default: true)
admin.previewProperties string[] Which of the target’s properties appear in the preview (max 3)

An embedding column, for nearest-neighbour search. Postgres only.

embedding: {
type: "vector",
name: "Embedding",
dimensions: 1536
}
Property Type Description
dimensions number Required. Length of the vector. Compiles to VECTOR(n).
index VectorIndexConfig | false How the ANN index is built. Omitted, one HNSW index for cosine distance. false creates none.

An ANN index is created with the column, so vectorSearch is approximate and fast rather than an exact scan. It is built for cosine distance, which is what vectorSearch measures with unless you pass distance — an index serves exactly one operator, so an l2 query against a cosine index quietly goes back to scanning. method (hnsw or ivfflat), distance (one or several), m, efConstruction and lists are all on index. Above 2000 dimensions pgvector can build neither index type, so the column is left unindexed and the boot says so.

Query it with .vectorSearch(), which also covers what pgvector needs to be installed and how to tune the index. For ordinary btree, GIN and BRIN indexes on any collection, see Indexes.

Raw bytes, stored as bytea. Values cross the API as base64 strings — including defaultValue.

signature: {
type: "binary",
name: "Signature"
}

Large files belong in storage, not in a column: a bytea is read and written whole, with the row.

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