Intercept everything.
Before and after hooks on every operation. Transform data, enforce business rules, trigger side effects with full access to the request context and Direct API.
What it does
Nextly's hook system lets you run custom logic before or after any database operation. Hooks are defined directly in your collection configurations using thehooksproperty, or registered globally with the*wildcard.
Before hooks can modify the data being written or throw an error to abort the operation. After hooks are for side effects: send notifications, revalidate caches, or log audit events. Each hook receives a context object with the user, operation type, data, and a reference to the Nextly Direct API for performing additional database operations within the hook.
The hook system supports 8 collection-level hooks that cover every stage of a CRUD lifecycle. Hooks run in registration order, and each before hook receives the data returned by the previous one, enabling a pipeline pattern.
8 Collection Hooks
beforeOperation, beforeValidate, beforeChange, afterChange, beforeRead, afterRead, beforeDelete, afterDelete. Cover every stage of a CRUD operation.
Global Wildcards
Register hooks for all collections with the * wildcard. Perfect for audit logging, rate limiting, or cross-cutting validation.
Data Transformation
Before hooks return modified data that flows through the pipeline. Auto-generate slugs, set audit fields, and normalize values, all before the database write.
Error Control
Throw an error in any hook to abort the operation. Enforce business rules before data touches the database.
How hooks execute
Global hooks (registered with *) execute before collection-specific hooks. Multiple hooks on the same point run in registration order, and each receives the data returned by the previous hook.
Real-world patterns
Auto-generate slug from title
Use beforeChange to automatically create a URL-friendly slug whenever a post is created or its title changes.
import { defineCollection, text, richText } from"@revnixhq/nextly/config";
export default defineCollection({
slug:"posts",
fields: [
text({ name:"title", required: true }),
text({ name:"slug", unique: true }),
richText({ name:"content" }),
],
hooks: {
beforeChange: [
async ({ data, operation }) => {
if (data?.title && (operation ==="create" || !data.slug)) {
return {
...data,
slug: data.title.toLowerCase().replace(/\s+/g,"-"),
};
}
return data;
},
],
},
});Revalidate cache after changes
Use afterChange to revalidate your Next.js cache whenever content updates, so your frontend always shows fresh data.
hooks: {
afterChange: [
async ({ collection }) => {
// Revalidate Next.js cache for this collection
await fetch("/api/revalidate?tag=" + collection, {
method:"POST",
});
},
],
},Prevent deletion of published content
Throw an error in beforeDelete to abort the operation.
hooks: {
beforeDelete: [
async ({ data }) => {
if (data?.status ==="published") {
throw new Error("Cannot delete published posts. Unpublish first.");
}
},
],
},All hook points
| Hook | Timing | Operation | Description |
|---|---|---|---|
| beforeOperation | Before | Any | Runs before any operation. Modify operation arguments. Global hooks run first. |
| beforeValidate | Before | Create / Update | Runs before validation on create and update. Alias for beforeCreate + beforeUpdate. |
| beforeChange | Before | Create / Update | Runs before database write on create and update. Return modified data. |
| afterChange | After | Create / Update | Runs after database write on create and update. Side effects only. |
| beforeRead | Before | Read | Runs before database query. Modify query parameters. |
| afterRead | After | Read | Runs after database query. Transform response data. |
| beforeDelete | Before | Delete | Runs before database delete. Throw to prevent deletion. |
| afterDelete | After | Delete | Runs after database delete. Cleanup side effects. |
Internally, beforeChange maps to bothbeforeCreate andbeforeUpdate in the hook registry. Similarly, afterChange maps toafterCreate andafterUpdate.
Start building with Nextly
Free, open source, and yours to own. No sign-up required.
npx create-nextly-app@latest