Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/get-convex/better-auth/llms.txt

Use this file to discover all available pages before exploring further.

Triggers are a Convex-first approach to running mutations when your Better Auth data changes. Better Auth already supports this behavior for some tables through databaseHooks configuration, but database hooks cannot currently run in the same transaction as the original operation. Triggers run in the same transaction as the original operation, and work on any table in your Better Auth schema.

Configuration

To enable triggers, pass the triggers option to the component client config. A trigger config object has table names as keys, and each table name can be assigned an object with any of onCreate, onUpdate, or onDelete hooks. Enabling triggers also requires an authFunctions config. Import internal from _generated/api and AuthFunctions from @convex-dev/better-auth, then assign internal.auth to a typed authFunctions constant and pass it alongside triggers. The onUpdate hook receives both the new and old document, so you can compare them to detect specific field changes.
A single Better Auth endpoint or auth.api call can perform multiple database interactions. Throwing an error in a trigger will only ensure the database operation that triggered it will fail — any previous operations in the same request will still commit.
convex/auth.ts
import { DataModel } from "./_generated/dataModel";
import { components, internal } from "./_generated/api";
import { createClient, type AuthFunctions } from "@convex-dev/better-auth";

const authFunctions: AuthFunctions = internal.auth;

export const authComponent = createClient<DataModel>(components.betterAuth, {
  authFunctions,
  triggers: {
    user: {
      onCreate: async (ctx, doc) => {
        await ctx.db.insert("posts", {
          title: "Hello, world!",
          authId: doc._id,
        });
      },
      onUpdate: async (ctx, newDoc, oldDoc) => {
        // Both old and new documents are available so you can compare and detect
        // changes - you can ignore oldDoc if you don't need it.
      },
      onDelete: async (ctx, doc) => {
        // The entire deleted document is available
      },
    },
  },
});

export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi();
The onCreate, onUpdate, and onDelete exports come from authComponent.triggersApi(). Export them from your convex/auth.ts file so they are registered as Convex functions.