Features / Lifecycle Hooks

Lifecycle Hooks.

8 collection hooks: beforeOperation, beforeValidate, beforeChange, afterChange, beforeRead, afterRead, beforeDelete, afterDelete. Transform data, enforce rules, trigger side effects.

Nextly's hook system lets you run custom logic before or after any database operation. Hooks are defined directly in your collection configurations using the hooks property, 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.

Key capabilities

  • 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

  1. beforeOperation — global + collection-specific
  2. beforeValidate — create & update only
  3. beforeChange / beforeRead / beforeDelete — modify data or abort
  4. Validation + database operation
  5. afterChange / afterRead / afterDelete — side effects only

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 "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

  • 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 both beforeCreate and beforeUpdate in the hook registry. Similarly, afterChange maps to afterCreate and afterUpdate.

Start building with Nextly

Free, open source, and yours to own. No sign-up required.

Terminal