← All packages

Database · Convex component

@sholajegede/convex-cascading-deletes

A convex cascading deletes component for Convex.

npm install @sholajegede/convex-cascading-deletes
5,590downloads last week
47,235downloads last 12 months
v0.1.2latest, Mar 13, 2026
3releases since Mar 13, 2026

Downloads

Download history

Loading download history…

Build this

Build with @sholajegede/convex-cascading-deletes

The install and setup steps from the package documentation.

  1. 1

    Installation

    sh
    npm install @sholajegede/convex-cascading-deletes

    Add the component to your convex/convex.config.ts:

    ts
    import { defineApp } from "convex/server";
    import convexCascadingDeletes from "@sholajegede/convex-cascading-deletes/convex.config.js";
    
    const app = defineApp();
    app.use(convexCascadingDeletes);
    
    export default app;
  2. 2

    Usage

    Instantiate the client once, declaring your table relationships:

    ts
    // convex/cascadeDeletes.ts
    import { components } from "./_generated/api.js";
    import { CascadingDeletes } from "@sholajegede/convex-cascading-deletes";
    
    export const cascadingDeletes = new CascadingDeletes(components.convexCascadingDeletes, {
      relationships: [
        {
          sourceTable: "posts",      // child table
          targetTable: "users",      // parent table
          indexName: "by_user",      // index on posts that references users
          fieldName: "userId",       // field on posts that holds the user ID
        },
        {
          sourceTable: "comments",
          targetTable: "posts",
          indexName: "by_post",
          fieldName: "postId",
        },
      ],
    });

    Delete with cascade

    ts
    // convex/users.ts
    import { action } from "./_generated/server.js";
    import { cascadingDeletes } from "./cascadeDeletes.js";
    import { v } from "convex/values";
    
    export const deleteUser = action({
      args: { userId: v.string() },
      handler: async (ctx, args) => {
        const counts = await cascadingDeletes.deleteWithCascade(ctx, {
          table: "users",
          id: args.userId,
        });
        // counts: { users: 1, posts: 4, comments: 12 }
        return counts;
      },
    });

    Deleting a user cascades to their posts, then to each post's comments — all automatically, in the correct order.

    Enforce cascade-only deletions

    ts
    export const updatePost = mutation({
      args: { postId: v.id("posts"), title: v.string() },
      handler: async (ctx, args) => {
        const db = cascadingDeletes.getSafeDb(ctx);
        // db.delete() now throws — use deleteWithCascade instead
        await db.patch(args.postId, { title: args.title }); // fine
      },
    });

    Query deletion logs

    ts
    // convex/logs.ts
    import { query } from "./_generated/server.js";
    import { components } from "./_generated/api.js";
    import { v } from "convex/values";
    
    export const getDeletionLog = query({
      args: { table: v.string(), id: v.string() },
      handler: async (ctx, args) => {
        return await ctx.runQuery(components.convexCascadingDeletes.lib.getDeletionLog, {
          rootTable: args.table,
          rootId: args.id,
        });
      },
    });
    tsx
    // React — subscribes reactively
    const log = useQuery(api.logs.getDeletionLog, { table: "users", id: userId });
    // log.deletedCounts — JSON string: { "users": 1, "posts": 4, "comments": 12 }
    // log.deletedAt     — timestamp of when the cascade ran

    Validate indexes at startup

    ts
    export const onStartup = mutation({
      handler: async (ctx) => {
        await cascadingDeletes.validate(ctx);
      },
    });