payload-smart-deletion
Cascading deletes for Payload CMS relationship fields, inspired by PostgreSQL referential actions.

Overview
Mark relationship fields with a cascade action and the plugin handles the rest. When a document is deleted, all referenced documents are deleted too. When trash is enabled, cascades follow soft-delete and restore transitions through the entire document tree.
Features
- Hard-delete cascade -- permanently deletes referenced documents when the parent is deleted.
- Soft-delete cascade -- trashes referenced documents when the parent is trashed.
- Restore cascade -- restores referenced documents when the parent is restored.
- Polymorphic support -- works with single and polymorphic (
relationTo: [...]) relationships.
- Nested field support -- finds cascade fields inside groups, tabs, and blocks.
- Automatic trash propagation -- optionally enables
trash: true on target collections that need it.
Installation
pnpm add payload-smart-deletion
Usage
1. Add the plugin
Important: smartDeletionPlugin scans all collections at config time. It must be listed after any plugin that injects cascade relationship fields, so those fields are visible during the scan.
import { buildConfig } from "payload";
import { discussionsPlugin } from "payload-discussions";
import { smartDeletionPlugin } from "payload-smart-deletion";
export default buildConfig({
plugins: [
discussionsPlugin({ collections: ["posts"] }),
smartDeletionPlugin(),
],
});
2. Mark relationship fields
Add custom.smartDeletion: 'cascade' to any relationship field that should cascade deletes:
const Posts: CollectionConfig = {
slug: "posts",
trash: true,
fields: [
{
name: "comments",
type: "relationship",
relationTo: "comments",
hasMany: true,
custom: { smartDeletion: "cascade" },
},
],
};
Deleting a post now deletes all its comments. If the post is trashed, comments are trashed too. Restoring the post restores the comments. Cascades are recursive -- if the target collection also has cascade fields, they are followed automatically.
Plugin options
autoEnableTrash | boolean | true | When the source collection has trash: true, automatically enable trash: true on target collections. When false, logs a warning instead. |
Trash behavior
Soft-delete and restore hooks are only registered when the source collection has trash: true. If a target collection does not have trash enabled:
- With
autoEnableTrash: true (default): the plugin enables it automatically.
- With
autoEnableTrash: false: a warning is logged and cascaded deletes will hard-delete target documents instead of trashing them.
Contributing
This plugin lives in the payload-plugins monorepo.
Development
pnpm install
pnpm --filter payload-smart-deletion dev
pnpm --filter sandbox dev
The sandbox/ directory is a Next.js + Payload app that imports plugins via workspace:* -- use it to test changes locally.
Code quality
- Formatting & linting -- handled by Biome, enforced on commit via husky + lint-staged.
- Commits -- must follow Conventional Commits with a valid scope (e.g.
fix(payload-smart-deletion): ...).
- Changesets -- please include a changeset in your PR by running
pnpm release.
Issues & PRs
Bug reports and feature requests are welcome -- open an issue.
License
MIT