3.5 KiB
3.5 KiB
| title | aliases | tags | sources | created | updated | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Trash — Soft Delete |
|
|
|
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
deletedAttimestamp - 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:
- Trashing →
data.deletedAtis set to a timestamp - Permanent delete →
dataisundefined
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: trueon the wiki/payloadcms/collection-config deletedAtfield is auto-injected; set on soft-delete, cleared on restore- Default delete from list view = soft delete; checkbox overrides to permanent
trash: truequery param includes trashed docs — combine withwhere: { deletedAt: { exists: true } }to get only trashed- wiki/payloadcms/access-control
deletefunction can distinguish trash vs permanent viadata.deletedAt - Must restore document from trash before restoring any of its versions
- Similar access control pattern to publish (
data._status) — usedataarg to differentiate operations
Sources
raw/trash__overview.md(https://payloadcms.com/docs/trash/overview)