Soft Deletes: The Feature That Costs More Than It Saves

Soft deletes look simple: add a deleted_at column, filter it in every query, ship it. They're in every ORM tutorial, every SaaS boilerplate, every "how to build a multi-tenant app" guide. They feel like free insurance. In practice, they're a slow-motion schema disaster that corrupts indexes, breaks constraints, and creates invisible data leaks that compound for years.

The appeal is real — hard deletes are scary, and deleted_at gives you an undo button. But there's a significant gap between what soft deletes promise and what they cost at scale.