Content Types
Field Types
17 field types, common options, type-specific configuration, and validation rules.
Content Types support 17 field types. Each field is defined as [[fields]] with a field_type and optional constraints.
Field Type Reference
| Type | SQLite | MySQL | PostgreSQL | Use For |
|---|---|---|---|---|
text | TEXT | VARCHAR(255) | VARCHAR(255) | Short text — titles, names, URLs |
richtext | TEXT | TEXT | TEXT | Long-form content — HTML, Markdown |
integer | INTEGER | INT | INTEGER | 32-bit whole numbers |
bigint | INTEGER | BIGINT | BIGINT | 64-bit whole numbers |
decimal | TEXT | DECIMAL(16,4) | NUMERIC(16,4) | Precise decimals — prices, amounts |
float | REAL | DOUBLE | DOUBLE PRECISION | Floating-point numbers |
boolean | BOOLEAN | TINYINT(1) | BOOLEAN | True / false flags |
date | TEXT | DATE | DATE | Date values (ISO 8601) |
datetime | TEXT | DATETIME | TIMESTAMPTZ(0) | Timestamps (ISO 8601) |
time | TEXT | TIME | TIMETZ | Time values (ISO 8601) |
email | TEXT | VARCHAR(255) | VARCHAR(255) | Email addresses (format-validated) |
password | TEXT | VARCHAR(255) | VARCHAR(255) | Password strings |
enum | TEXT | VARCHAR(255) | VARCHAR(255) | Fixed value list |
uid | TEXT | VARCHAR(255) | VARCHAR(255) | Auto-generated slug / UID |
json | TEXT | JSON | JSONB | Arbitrary structured data |
media | TEXT | VARCHAR(255) | VARCHAR(255) | File / image uploads |
relation | INTEGER | BIGINT | BIGINT | Related record reference |
Common Options
All field types share these options:
[[fields]]
name = "title"
field_type = "text"
required = true
unique = true
default = "Untitled"
private = false
immutable = false
label = "Title"
description = "The display title"
max_length = 200
min = 0
max = 100
pattern = "^[A-Z]"| Option | Type | Default | Description |
|---|---|---|---|
required | bool | false | Must be provided on create |
unique | bool | false | Database uniqueness constraint |
default | any | — | Default value (string, number, bool, null) |
private | bool | false | Hidden from public API, visible in admin API |
immutable | bool | false | Cannot be changed after creation |
label | string | — | Display label for admin UI |
description | string | — | Field description |
max_length | int | — | Maximum string length |
min | float | — | Minimum numeric value |
max | float | — | Maximum numeric value |
pattern | string | — | Regex validation pattern |
Type-Specific Options
enum
Must provide enum_values:
[[fields]]
name = "priority"
field_type = "enum"
enum_values = ["low", "medium", "high"]
default = "medium"uid
Auto-generates a URL-safe slug from another field:
[[fields]]
name = "slug"
field_type = "uid"
target_field = "title"
unique = truemedia
Control accepted file types and count:
[[fields]]
name = "cover"
field_type = "media"
media_config = { accept = ["image/*"], max_count = 1 }| Option | Description |
|---|---|
accept | Array of MIME type patterns (e.g. ["image/*", "application/pdf"]) |
max_count | Maximum number of files (default: 1) |
relation
See Relations for the full guide.
[[fields]]
name = "author"
field_type = "relation"
relation = { relation_type = "many_to_one", target = "users" }Validation Rules
The system validates input automatically on every create and update:
| Check | When | How |
|---|---|---|
| required | Create | Field must exist and be non-null / non-empty |
| immutable | Update | Field must not be present in the update payload |
| type check | Create / Update | Value type must match field type |
| enum_values | Create / Update | Value must be in the allowed list |
| max_length | Create / Update | String length must not exceed limit |
| min / max | Create / Update | Numeric range validation |
| pattern | Create / Update | Value must match the regex |
| unique | Create / Update | DB uniqueness check (excludes self on update) |
Validation errors return 422 Unprocessable Entity with field-level details:
{
"error": "Validation failed",
"details": {
"email": "must be a valid email address",
"age": "must be greater than or equal to 18"
}
}Indexes
Define database indexes separately from fields:
[[indexes]]
fields = ["slug"]
unique = true
[[indexes]]
fields = ["status", "created_at"]| Option | Type | Description |
|---|---|---|
fields | string[] | Column names to index |
unique | bool | Whether the index is unique (default: false) |
