Validation and conditions
Enum Values
Section titled “Enum Values”Used with string or number properties to render selects:
// Simple arrayenum: ["draft", "published", "archived"]
// With labelsenum: [ { 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
Section titled “Validation”Every rule lives in the property’s validation block, and which rules a
property accepts depends on its type — min counts characters on a string,
compares magnitudes on a number, and counts elements on an array.
properties: { title: { type: "string", name: "Title", validation: { required: true, min: 2, max: 200 } }, slug: { type: "string", name: "Slug", validation: { unique: true, matches: /^[a-z0-9-]+$/, matchesMessage: "Lowercase letters, digits and hyphens only", trim: true, lowercase: true } }, readingMinutes: { type: "number", name: "Reading time", validation: { integer: true, moreThan: 0, max: 120 } }}Every type
Section titled “Every type”| Rule | Type | Description |
|---|---|---|
required |
boolean |
The value must be present |
requiredMessage |
string |
What the form says when it is not. Admin form only — not enforced by the API or the database. |
unique |
boolean |
Only one row in the table may hold this value |
uniqueInArray |
boolean |
Only one entry per array may hold it. Applies to a direct child of an array property, or a first-level child of a map inside one. Admin form only — not enforced by the API or the database. |
Strings
Section titled “Strings”| Rule | Type | Description |
|---|---|---|
min / max |
number |
Fewest / most characters, inclusive. A max also sizes the column: it turns TEXT into VARCHAR(max), so lowering it on a table that already holds longer rows is a migration the database refuses |
length |
number |
Exactly this many characters — a country code, a fixed-width reference |
matches |
string | RegExp |
A pattern the whole value must match. A string is compiled per request, so one that will not compile is rejected at boot rather than quietly becoming no rule |
matchesMessage |
string |
What the form says when matches fails |
trim |
boolean |
Strip leading and trailing whitespace before saving. A transform, not a check — it changes what is written, which is what makes it the fix for “the same tag twice, one with a trailing space”. Admin form only — not enforced by the API or the database. |
lowercase / uppercase |
boolean |
Case-fold the value before saving, like trim. Admin form only — not enforced by the API or the database. |
Email and URL formats are not validation rules. email and url are flags
on the property itself, beside type — statements about the data that the
OpenAPI contract is generated from, rather than form behaviour:
properties: { email: { type: "string", name: "Email", email: true }, website: { type: "string", name: "Website", url: true }}See String properties.
Numbers
Section titled “Numbers”| Rule | Type | Description |
|---|---|---|
min / max |
number |
Smallest / largest accepted value, inclusive |
moreThan / lessThan |
number |
The exclusive twins of min and max |
positive / negative |
boolean |
Strictly above / below zero. 0 is rejected by both — use min: 0 to allow it |
integer |
boolean |
No fractional part. Does not change the column type; columnType does |
| Rule | Type | Description |
|---|---|---|
min / max |
Date |
Earliest / latest accepted date, inclusive. A fixed instant, not “today” |
Arrays
Section titled “Arrays”| Rule | Type | Description |
|---|---|---|
min / max |
number |
Fewest / most elements, inclusive. Elements, not characters |
Conditional Fields
Section titled “Conditional Fields”You can make fields dynamic so they react to the entity’s values. There are two ways to do this:
1. JSON Logic Conditions (Declarative)
Section titled “1. JSON Logic Conditions (Declarative)”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,disabledMessage,clearOnDisabled,hidden,readOnlyrequired,requiredMessage,min,maxdefaultValueenumConditions,allowedEnumValues,excludedEnumValuesreferencePath,referenceFiltercanAddElements,sortable(for arrays)acceptedFiles,maxFileSize(for uploads)
disabledMessage is the sentence a reader sees in place of the control. Without
it a greyed-out field explains nothing, which is the difference between a form
that is guiding someone and one that is refusing them.
2. Property Builders (Programmatic)
Section titled “2. Property Builders (Programmatic)”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 } })}The same caveat applies, and more sharply: the function is bundled into the panel and called on every render of the form. Admin form only — not enforced by the API or the database.
Next Steps
Section titled “Next Steps”- Properties — the property types these rules apply to
- Defining Collections — where properties are declared
- Security Rules (RLS) — the rules the database enforces, which validation does not replace