Fields & validation
The 16 field types Vaultbase supports, their options, and how validation runs server-side.
A field is one column on a collection. Vaultbase has 16 types, all with server-side validation, type-aware encoding, and per-field options.
Field types
Section titled “Field types”| Type | SQL storage | API shape | Notes |
|---|---|---|---|
text | TEXT | string | min/max length, regex pattern, unique |
number | REAL | number | min/max value, unique |
bool | INTEGER (0/1) | boolean | — |
email | TEXT | string | format-validated |
url | TEXT | string | http(s) only |
date | INTEGER (unix seconds) | number or ISO string on input | always returns number |
autodate | INTEGER | number | server-managed; opt-in onCreate / onUpdate |
select | TEXT (single) / TEXT JSON (multi) | string or string[] | values whitelist required, multi flag |
relation | TEXT (target id) | string | target collection name; cascade behavior; indexed automatically (single relations, since v0.26.5) |
file | TEXT (filename) / TEXT JSON (multi) | string or string[] | maxSize, mimeTypes, multiple, protected, thumbs |
json | TEXT (stringified) | any | round-tripped via JSON.parse |
password | TEXT (Argon2 hash) | write-only | hashed via Bun.password.hash; never returned |
editor | TEXT (HTML) | string | Quill rich text in admin |
geoPoint | TEXT JSON {lat,lng} | {lat,lng} | lat ∈ [-90,90], lng ∈ [-180,180] |
vector | TEXT JSON number[] | number[] | dimensions (1-4096) required; exact length, finite numbers |
color | TEXT | string | hex color, stored lowercase #rrggbb (#rrggbbaa with alpha); #rgb / any case accepted and normalised |
Field options
Section titled “Field options”All types accept these via the schema editor’s options panel:
required: bool— non-empty on create; for update, only checked if the field is provided (allows partial updates).unique: bool— uniqueness check at validate time, backed by a unique index in the database. Set it insideoptions("options": { "unique": true });requiredsits on the field itself.
Type-specific options:
// FieldOptions{ // text: min/max length; editor: max only; password: min/max min?: number; max?: number; pattern?: string; // regex; text only unique?: boolean;
// select values?: string[]; // required allowlist multiple?: boolean; // multi-select → string[]
// file maxSize?: number; // bytes mimeTypes?: string[]; // patterns; "image/*" supported multiple?: boolean; protected?: boolean; // gates GET behind a token — see Files thumbs?: string[]; // allowed ?thumb= sizes for non-admins, e.g. ["100x100", "800x0"]
// vector dimensions?: number; // 1-4096, required
// relation cascade?: "setNull" | "cascade" | "restrict";
// color alpha?: boolean; // also accept #rgba / #rrggbbaa (stored as #rrggbbaa)
// text / json (encryptable types) encrypted?: boolean; // AES-GCM at rest, requires VAULTBASE_ENCRYPTION_KEY
// text / editor / email / url searchable?: boolean; // full-text index, queried with ?search= (see Full-text search)}Validation flow
Section titled “Validation flow”Every create/update goes through validateRecord():
- Skip system fields, implicit fields (auth
email/verified), andautodatefields. - For each remaining field:
- Required check (create only — empty allowed on update unless explicitly
required). - Type check + per-type rules (length, range, pattern, format, allowed values).
- Unique check (DB query against
vb_<col>). - Relation existence check (DB query against the target table).
- File ownership check: a non-admin may only set a file field to files uploaded to that same record and field (admins are exempt).
- Required check (create only — empty allowed on update unless explicitly
- Aggregate all errors into a single
ValidationError— the API returns422withdetails: { fieldName: message }so clients can surface per-field errors at once.
Multi-error response example:
{ "error": "Validation failed", "code": 422, "details": { "title": "title must be at least 3 characters", "age": "age must be at least 18" }}Relation cascade
Section titled “Relation cascade”When you delete a record, Vaultbase finds every other collection with a relation field pointing at this one and applies the configured behavior:
setNull(default) — bulkUPDATEclearing the foreign key column.cascade— recursively delete referencing records (chains through multiple levels; cycle-protected).restrict— refuse the delete with409while references exist.
Order: restrict references are checked first, then the beforeDelete hook
runs (and can still refuse the delete), and only then are cascades applied.
A delete that cascades runs in a transaction: if any step fails (a nested
restrict, a hook error), nothing is deleted or nulled.
Encrypted fields
Section titled “Encrypted fields”For text/email/url/json fields, set encrypted: true in the options. Values
are encrypted with AES-GCM before insert (using VAULTBASE_ENCRYPTION_KEY)
and decrypted on read. Set the key once and persist it — losing it makes
encrypted values unreadable.
# Generate a 32-byte key (base64)openssl rand -base64 32export VAULTBASE_ENCRYPTION_KEY="<output>"System fields
Section titled “System fields”These are auto-generated and read-only:
id— UUID, set on createcreated_at(returned ascreated) — unix seconds, set on createupdated_at(returned asupdated) — unix seconds, refreshed on every update
Fields named id, created, updated, created_at, updated_at,
collectionId, collectionName or expand are refused with 422.
In filters and rules, created / created_at and updated / updated_at both work.