Soft delete plugin for Strapi v5 — never lose content again. Restore entries, auto-purge, lifecycle hooks, RBAC
released May 15, 2026
npm install strapi-soft-delete-pluginSoft delete plugin for Strapi v5 — never lose content again. When you delete an entry, it's marked as deleted instead of being removed from the database. You can restore it or permanently delete it later.
Drop-in replacement for strapi-plugin-soft-delete with significant improvements.
beforeSoftDelete, afterSoftDelete, beforeRestore, afterRestore, beforeDeletePermanently, afterDeletePermanentlybeforeUpdate/afterUpdate hooks| Strapi Version | Plugin Version |
|---|---|
| ^5.0.0 | 0.x |
| ^4.x | Use strapi-plugin-soft-delete |
npm install strapi-soft-delete-plugin
# or
yarn add strapi-soft-delete-pluginAdd to your plugin configuration:
// config/plugins.ts
export default () => ({
'soft-delete': {
enabled: true,
},
});Rebuild and start:
npm run build
npm run developAutomatically permanently delete soft-deleted entries older than a specified number of days:
// config/plugins.ts
export default () => ({
'soft-delete': {
enabled: true,
config: {
autoPurge: {
enabled: true,
ttlDays: 30, // permanently delete after 30 days
cron: '0 2 * * *', // run daily at 2 AM
},
},
},
});Configure per-role in Settings → Roles → [Role Name]:
| Section | Permission | Description |
|---|---|---|
| Collection & Single Types | Soft Delete | Soft delete entries (replaces "Delete") |
| Collection & Single Types | Deleted Read | View soft-deleted entries in the explorer |
| Collection & Single Types | Deleted Restore | Restore soft-deleted entries |
| Collection & Single Types | Delete Permanently | Permanently remove soft-deleted entries |
| Plugins → Soft Delete | Read | Access the Soft Delete explorer in the sidebar |
| Plugins → Soft Delete | Settings | Manage plugin settings |
Configure in Settings → Soft Delete → Restoration Behavior:
Single Type Restoration — when restoring a single type entry that already has an active entry:
Soft Delete — soft-delete the existing active entry (default)Delete Permanently — permanently delete the existing active entryDraft & Publish Restoration — when restoring an entry from a D&P content type:
Unchanged — preserve the original publish state (default)Draft — always restore as draftThe plugin works out of the box without any custom code. If you need to run custom logic during soft-delete operations (e.g., logging, notifications, validation), you can register lifecycle hooks in your application's bootstrap:
// src/index.ts
export default {
async bootstrap({ strapi }) {
const hooks = strapi.plugin('soft-delete').service('lifecycle-hooks');
hooks.register('beforeSoftDelete', async ({ uid, documentId, entries, auth }) => {
console.log(`About to soft-delete ${documentId} from ${uid}`);
// Return { cancel: true } to prevent the operation
});
hooks.register('afterRestore', async ({ uid, documentId, entries, auth }) => {
console.log(`Restored ${documentId} in ${uid}`);
});
},
};Available hooks:
beforeSoftDelete / afterSoftDeletebeforeRestore / afterRestorebeforeDeletePermanently / afterDeletePermanentlyAll before* hooks can return { cancel: true } to abort the operation.
_softDeletedAt, _softDeletedById, _softDeletedByType) to all api::* content types at boot timedelete operations into updates that set the soft-delete fields_softDeletedAt IS NULL into every query, hiding soft-deleted entries from normal API responses and populated relationsSee MIGRATION.md for a step-by-step guide.
# Install dependencies
npm install
# Build the plugin
npm run build
# Type check (server + admin + tests)
npm run type-check
# Lint
npm run lint
# Format
npm run format
# Unit tests
npm run test
# Unit tests with coverage
npm run test:coverage
# E2E tests (requires running Strapi instance)
npm run test:e2eShare your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.
Submit
