obsidian/wiki/payloadcms/trash-soft-delete.md
2026-05-15 16:48:40 +01:00

3.5 KiB

title aliases tags sources created updated
Trash — Soft Delete
soft-delete
trash
deletedAt
restore-documents
payloadcms
collections
admin-panel
access-control
api
raw/trash__overview.md
2026-05-15 2026-05-15

Overview

Trash (soft delete) marks documents as deleted without permanently removing them. Enable it per collection with trash: true. Payload injects a deletedAt timestamp field automatically.

export const Posts: CollectionConfig = {
  slug: 'posts',
  trash: true,
  fields: [...],
}

Admin Panel

  • New route added: /collections/:collectionSlug/trash
  • Trash view shows all documents with a deletedAt timestamp
  • Bulk actions: Restore, Delete (permanent), Empty Trash
  • Edit view of trashed document: all fields read-only; only Restore and Permanently Delete actions available
  • API / Versions / Preview tabs remain accessible from trashed doc edit view
  • Main list view delete → soft-deletes by default; checkbox in modal allows skipping trash

API — trash Parameter

Applies to: find, findByID, update, updateByID, delete, deleteByID, findVersions, findVersionByID

Goal Query
All documents (normal + trashed) trash: true
Only trashed trash: true + where: { deletedAt: { exists: true } }
Only non-trashed (explicit) trash: false

Local API

// Only trashed
const result = await payload.find({
  collection: 'posts',
  trash: true,
  where: { deletedAt: { exists: true } },
})

REST

GET /api/posts?trash=true&where[deletedAt][exists]=true

GraphQL

query {
  Posts(trash: true, where: { deletedAt: { exists: true } }) {
    docs { id deletedAt }
  }
}

Access Control

All trash actions (soft-delete, restore, permanent delete) respect the collection's delete access control.

The delete function receives data:

  • Trashingdata.deletedAt is set to a timestamp
  • Permanent deletedata is undefined

Pattern: editors can trash, only admins can permanently delete

access: {
  delete: ({ req: { user }, data }) => {
    if (!user) return false
    if (user.roles?.includes('admin')) return true
    // Allow trash (deletedAt being set), deny permanent delete
    if (data?.deletedAt) return true
    return false
  },
},

In the Admin Panel, when a user can trash but not permanently delete:

  • Delete button is visible
  • "Delete permanently" checkbox is hidden

Versions + Trash Interaction

  • A trashed document cannot have a version restored until the document itself is restored from trash
  • Attempting to restore a version of a trashed document throws an error
  • Version history is still visible from the trashed document's edit view

Key Takeaways

  • Enable with trash: true on the wiki/payloadcms/collection-config
  • deletedAt field is auto-injected; set on soft-delete, cleared on restore
  • Default delete from list view = soft delete; checkbox overrides to permanent
  • trash: true query param includes trashed docs — combine with where: { deletedAt: { exists: true } } to get only trashed
  • wiki/payloadcms/access-control delete function can distinguish trash vs permanent via data.deletedAt
  • Must restore document from trash before restoring any of its versions
  • Similar access control pattern to publish (data._status) — use data arg to differentiate operations

Sources