Schema Lifecycle Hooks
resolveInput, validate, beforeOperation, and afterOperation, plus beforeValidate / afterValidate, on collection create and update.
On this page
Optional transforms and validators on every document write path (Local API, HTTP, admin) for a collection schema. Field hooks live on field.hooks. List hooks live on the collection hooks object.
Order on create / update
- Field and list
resolveInput beforeValidate— normalize (trim, slugify, defaults)- Field and list
validate, together with the numeric/exact gate.validatemay return many errors; the write aborts once, before persist beforeOperationafterValidate— computed fields after the gate andbeforeOperation- Plugin / collection
beforeSavelifecycle modifyRequest(widget validation & transforms)- Persist (
insert/updateuses the final mutated payload) afterOperation(post-commit, not awaited — a failure is logged at debug and does not undo the write) alongsideafterSave+ transactional outbox emit
The same order is the contract in Schema model.
Defining hooks
import type { Schema } from "@src/content/types";
const posts: Schema = {
_id: "posts",
name: "Posts",
fields: [/* ... */],
hooks: {
beforeValidate: (data) => ({
...data,
slug:
data.slug ||
String(data.title || "")
.toLowerCase()
.replace(/\s+/g, "-"),
}),
afterValidate: (data) => ({
...data,
searchKey: `${data.title}:${data.slug}`,
}),
},
};
Hooks may be async. resolveInput, beforeValidate, beforeOperation, and afterValidate return the data object. validate collects errors and aborts once before the write. Do not throw from a transform to reject a document. Field hooks use the same names on field.hooks.
Pure runners (unit-test friendly)
import {
applyBeforeValidate,
applyAfterValidate,
applySchemaHookPipeline,
} from "@src/content/schema-hooks";
Implementation
- Types + runners:
src/content/schema-hooks.ts - Wired:
src/services/sdk/namespaces/collections-namespace.ts(create/update) - Tests:
tests/unit/content/schema-hooks.test.ts
Was this page helpful?