Deleting feels final — and sometimes it shouldn't be. Soft deletes give users a safety net and you an audit trail.
1model Task {
2 // ...
3 deletedAt DateTime?
4}1// Soft delete
2await prisma.task.update({
3 where: { id },
4 data: { deletedAt: new Date() },
5});This is the catch: every read now has to filter them out.
1await prisma.task.findMany({ where: { deletedAt: null, ownerId } });Forgetting the filter resurrects "deleted" data. Centralize it — a base where fragment, a Prisma extension, or a database view — so you can't forget.
1await prisma.task.update({ where: { id }, data: { deletedAt: null } });Instant "undo" / "restore from trash".
Soft delete isn't always right:
A common pattern: soft delete immediately, then hard delete rows whose deletedAt is older than 30 days.
Hard deletes can cascade via foreign keys (Chapter 2). Soft deletes can't — you must decide and implement: when a project is soft-deleted, do its tasks disappear too? Handle this explicitly in your service layer.