In SQL, when you DELETE, the row is gone permanently.
But in real-world applications:
| Case | Why deletion must be reversible |
|---|---|
| User deletes account | You may need recovery, legal retention, fraud audits |
| Admin deletes product | Orders still reference it |
| Messaging apps | Soft-delete chat but restore later |
| Fintech / Banking | Permanent deletion is often illegal |
So instead of actually deleting the row, we mark it as deleted, but keep the data.
User Modelconst User = sequelize.define("User", {
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: UUIDV4,
},
name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING,
}, {
tableName: "users",
paranoid: true, // ✅ enable soft delete
timestamps: true // must be true to track deletedAt
});
Sequelize automatically adds a hidden column:
deletedAt TIMESTAMP NULL
| Action | Result |
|---|---|
destroy() |
Sets deletedAt = current timestamp |
find() queries |
Will NOT return soft-deleted rows |
restore() |
Sets deletedAt = null (undo delete) |
await User.destroy({
where: { id: userId }
});
This does NOT remove row from DB, instead:
| Field | Before | After |
|---|---|---|
deletedAt |
NULL |
2025-10-30 14:12:33.123 |
const activeUsers = await User.findAll(); // soft-deleted rows excluded