Backend Development › Relational Databases & SQL
Soft Delete
Marking rows as deleted instead of removing them.
Also known as: soft delete, soft deletes, logical delete
A soft delete keeps a row in the table but marks it deleted — usually a deleted_at timestamp (or an is_deleted flag). The row is hidden from normal queries but never physically removed. It preserves history and referential integrity: a deleted user’s orders still point at a real row.
hard delete: DELETE FROM users WHERE id = 42; (row gone)
soft delete: UPDATE users SET deleted_at = now() WHERE id = 42; (row hidden)
Why teams do it: undo, audit trails, and avoiding broken foreign keys when related data exists. Deleting a customer who has invoices is often wrong; marking them deleted keeps the invoices valid.
The classic mistakes:
- Forgetting to filter. The signature soft-delete bug: a query that doesn’t add
WHERE deleted_at IS NULLreturns deleted records. Every read must filter — one missed join and deleted data reappears. Enforce it centrally (a default scope, a view, or row-level security). - Unique constraints vs soft deletes. A unique constraint on email blocks a new user with the same email as a soft-deleted one. You need a partial unique index (
WHERE deleted_at IS NULL) or a different scheme. - Treating it as free. Deleted rows accumulate; tables grow, scans slow, and storage cost rises. Soft delete is deferral, not deletion — plan eventual hard deletion or archiving.
- Privacy and retention conflicts. Regulations may require actual deletion (“right to be forgotten”). A soft delete that keeps personal data can violate that. Know which data must truly go (see GDPR).
- Cascading confusion. With soft deletes, cascading deletes don’t happen; you must handle related rows explicitly, or orphaned “live” children of a “deleted” parent appear.
- No audit of who deleted what. A
deleted_atalone loses who and why; add audit columns or use record history.
When to use it: when you need undo, referencing or history, and rarely hard-delete. Combine it with a strict, central filter, a partial unique index, and a retention plan for eventual removal. For genuinely disposable data, a hard delete is simpler and honest — don’t soft-delete everything by reflex.