Skip to main content

Soft Deletes and Restore

Use this page when records should be recoverable instead of permanently removed.

When delete() is soft

delete() behaves as a soft delete when the model has a deleted_at soft-delete field in its schema. Valid schema patterns:
For PostgreSQL-focused apps, prefer the explicit timezone-aware form:
or:
Do not define both at once.

What soft delete does

Soft delete updates deleted_at instead of permanently removing the record. Typical service call:

How restore() works

restore() clears deleted_at and makes the record visible again to normal reads.

Hard delete after soft delete

Use forceDelete() only when the record should be permanently removed:
After forceDelete(), do not assume restore() can recover the record.

Querying deleted records

  • controllers expose restore routes when recovery is part of the API
  • services own restore, onlyTrashed, withTrashed, and forceDelete
  • models define the schema requirement

Safe usage notes

  • use soft delete for recoverable business entities
  • use forceDelete only in admin or cleanup paths
  • do not document restore as guaranteed after force delete
  • keep restore paths covered in tests