1Hard vs Soft
While Soft Deletes are standard practice for data retention and analytics, laws like GDPR complicate things. If a user requests a 'Right to be Forgotten' deletion, a Soft Delete is illegal. You must execute a Hard DELETE command and physically scrub their PII from your database and backups.
2Step-by-Step Breakdown
The Syntax. DELETE removes entire rows from a table. The syntax is simple: 'DELETE FROM table_name'.
The Golden Rule of DELETE. Exactly like UPDATE, NEVER run a DELETE statement without a WHERE clause. 'DELETE FROM users;' will empty the entire table.
Targeted Deletion. Always delete by Primary Key if possible. 'DELETE FROM users WHERE id = 5;'. This is the safest way to ensure only one specific record dies.
Foreign Key Constraints. If User 5 has written 10 'Orders', and you try to delete User 5, the database might throw a 'Foreign Key Constraint' error. You cannot delete a parent if children rely on it.
Knowledge Check. What happens if you try to DELETE a user who currently has 5 active orders linked to their User ID, assuming standard Foreign Key protections are active?
- →The user is deleted and the orders remain
- →The database aborts the deletion and throws a constraint error
ON DELETE CASCADE. When you created the 'Orders' table, you could have set the foreign key to 'ON DELETE CASCADE'. If you do this, deleting User 5 will automatically and silently delete all their 10 orders too.
Soft Deletes. In professional backends, we rarely use the DELETE command. Instead, we use 'Soft Deletes'. We add a column called 'is_deleted BOOLEAN'. When a user deletes their account, we run an UPDATE to set is_deleted = true.
Handling Soft Deletes. If you use Soft Deletes, EVERY single SELECT query in your entire app must now include 'WHERE is_deleted = false'.
RETURNING. You can use RETURNING on a DELETE statement. 'DELETE FROM users WHERE id = 5 RETURNING *;'. This gives you the data of the user you just destroyed, just in case.
Summary. DELETE is permanent. Use Soft Deletes for safety in production.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1'Delete Account' Buttons Require a Real Confirmation Step
Any UI action that maps to a DELETE (or soft-delete UPDATE) statement — like a 'Delete Account' button — needs a keyboard-accessible confirmation dialog with a clear, non-ambiguous label, not just a color change, since screen reader users can't rely on a red button to signal irreversibility.
SEO Implications
- 1
Soft Deletes Prevent Broken Links From Suddenly 404ing
If a public-facing page (e.g. a user profile or product listing) is backed by a hard DELETE, the URL immediately 404s the moment the record is removed, killing any accumulated SEO value — a soft delete (is_deleted flag) lets you serve a proper 410 Gone or redirect instead of an abrupt broken link.
Best Practices
Never Write DELETE Without a WHERE Clause Already Typed
Get in the habit of writing 'DELETE FROM table WHERE id = $1' with the WHERE clause first before filling in the table name, so you never accidentally execute a bare DELETE FROM users; that wipes the entire table.
Prefer Soft Deletes for User-Facing Data, Reserve Hard Deletes for Compliance
Use an is_deleted boolean column and UPDATE instead of DELETE for most application data so mistakes are reversible, but keep a genuine hard DELETE path available for legally required erasure requests like GDPR's Right to be Forgotten.
Frequent Bugs
Deleting a user throws a foreign key constraint error because they still have related rows (e.g. orders) pointing at them.
The database refuses to delete a parent row while dependent child rows reference it, to protect referential integrity. Either delete the child rows first, or define the foreign key with ON DELETE CASCADE if you actually want the children removed automatically.
Real-World Examples
Safely Deleting a User and Returning Their Data for an Audit Log
An account-deletion API endpoint needed to remove a single user by primary key and log exactly what was deleted, without accidentally affecting any other row.
DELETE FROM users
WHERE id = 5
RETURNING id, email, created_at;