How do you implement soft deletes and undelete safely?
Soft delete is a pattern where a record is marked as deleted without being physically removed. You keep the data in primary storage but hide it from normal reads and write paths. Undelete is the controlled reversal that restores the record and every dependent artifact such as caches search documents and derived aggregates. This pattern gives you safety observability and compliance without breaking user expectations. In a system design interview you will impress when you show how soft delete and undelete flow through storage indexing caching streaming and authorization.
Why It Matters
Real systems need safety rails. Users change their minds. Customer support needs to recover data quickly. Legal teams need audit trails. Product teams need analytics on churned items. Hard delete removes all of that context immediately. Soft delete keeps the ability to roll back while enforcing privacy policies through scheduled purge. In interviews it shows senior judgment about data lifecycle risk control and scalable architecture choices in distributed systems.
How It Works (Step-by-Step)
1. Model the State
Add fields such as deleted_at, deleted_by, and delete_reason. Use a timestamp instead of a boolean since it helps with retention policies and time-based analytics. Treat deletion as a state transition: active → deleted → purged.
2. Apply Filters at the Data Boundary Ensure every read path automatically excludes deleted records. Use database views, ORM-level global filters, or service-layer policies. Add observability counters to track accidental reads of deleted rows.
3. Maintain Uniqueness Correctly
Soft deletes can break unique constraints. Use partial indexes that enforce uniqueness only for active rows or include the deleted_at column in composite keys. During undelete, validate that no active record now holds the same unique field.
4. Make Deletes Idempotent and Auditable A delete request should only mark the record and emit an event (tombstone). Repeated requests should be safe and return the same result. Always log who deleted it, when, and why in an audit trail.
5. Propagate Changes to Derived Stores Broadcast tombstone events to dependent systems such as caches, search indexes, or analytics stores. These consumers should invalidate or remove the data consistently and idempotently.
6. Add Retention and Purge Policies Schedule jobs to permanently remove soft-deleted data after a fixed retention window. Track purge latency and reclaimed storage for operational health.
7. Implement Safe Undelete Undelete should:
- Validate conflicts or constraint violations
- Clear deletion markers
- Rebuild caches and search indexes
- Publish an undelete event Make it idempotent to avoid partial restores if the operation is retried.
8. Test and Monitor Automate checks to ensure deleted data doesn’t leak into user views. Track metrics for delete, undelete, and purge operations. Alert on failures or inconsistencies across systems.
Real World Example
Think about a photo in a social app. When a user taps delete the photo should disappear from feeds search and notifications right away. Internally the media row is marked deleted at now plus user id and reason. The service publishes a tombstone event that removes the item from search and invalidates feed caches. Customer support has thirty days to restore the photo if the user contacts support. If the user restores it from a recently deleted view the system checks whether any unique constraints such as a short link still collide and then clears the marker reindexes the document and repopulates any timeline aggregates. After the retention window a nightly purge job removes the row the media file and any related comments or likes that are no longer needed.
Common Pitfalls or Trade offs
Query leaks Teams forget to filter out deleted rows in new endpoints or ad hoc queries. Solve this with default scopes database views and automated tests that assert the filter.
Uniqueness collisions on restore Undelete fails because another active record now holds the unique value. Use partial indexes and a preflight conflict check that offers a merge or rename workflow.
Orphaned children Deleting a parent while children remain active can break invariants. Choose clear rules cascade to mark children deleted restrict delete when children exist or move children to a safe container during retention.
Derived store skew Search caches and analytics might lag behind. Use reliable event delivery and idempotent consumers. Add a reconciliation job that scans for mismatches between primary storage and derived stores.
Privacy and right to erasure Soft delete alone is not compliance. You still need a purge plan that removes data fully within policy windows. Keep audit metadata only if policies allow.
Storage bloat and performance Large tables with many deleted rows can slow queries. Use partial indexes prune partitions and compact storage through purge. For object stores enable lifecycle rules that transition old blobs to cheaper tiers before deletion.
Ambiguous product behavior Users expect immediate disappearance but support needs to restore. Provide a clear recently deleted experience and notify the user about retention policy.
Interview Tip
Clarify the life cycle at the whiteboard. Say that delete is a reversible state change that publishes a tombstone event while purge is an irreversible operation. Then outline how you will enforce uniqueness for active rows and how undelete rebuilds search caches and projections. Finish with an idempotent flow and an audit log that records who did what and when.
Key Takeaways
-
Soft delete marks data as deleted while keeping it available for restore analytics and audit
-
Undelete is a first class workflow with conflict checks reindex and cache warm up
-
Always filter deleted rows at the data boundary and enforce uniqueness for active rows
-
Publish deletion and restoration events so every consumer updates caches and search
-
Add retention and purge to meet privacy and cost goals
Table of Comparison
| Approach | Description | Pros | Cons | Typical Use | Undelete Support |
|---|---|---|---|---|---|
| Soft Delete | Marks data with a deletion flag and hides from reads | Easy recovery, full audit, low risk | Increases storage size, potential query leaks | Apps needing restore & audit trails | ✅ Yes |
| Hard Delete | Physically removes data | Simple, storage efficient | Irreversible, no audit | Data easy to recompute or privacy critical | ❌ No |
| Archive Table | Moves deleted rows to a separate table | Keeps primary fast, recoverable | Slower restore, higher complexity | Large transactional systems | ✅ Yes |
| Object Versioning | Stores delete markers in object storage | Great for media & blobs | Needs coordination with metadata | File or document storage | ✅ Yes |
| Event Log Tombstone | Publishes delete events for consumers | Works in event-driven systems | Requires strict contracts | Streaming & CQRS designs | ✅ Yes |
FAQs
Q1. Is soft delete the same as archive?
No. Soft delete keeps the row in place with a marker and hides it from reads. Archive moves data to a different table or store to keep hot paths small.
Q2. How do I enforce unique keys with soft delete?
Use partial indexes that apply only to active rows or include the deletion marker in a composite unique key. On undelete run a conflict check and repair by merge or rename.
Q3. How long should I retain deleted data before purge?
Pick a policy based on user expectations and legal rules such as thirty or ninety days. Document it and enforce it with a scheduled purge that also removes blobs and derived data.
Q4. How does undelete work in microservices?
Treat restore as a workflow. The owning service clears the marker then republishes a resource restored event. Consumers rebuild search documents counters and caches. Make every step idempotent.
Q5. Does soft delete satisfy right to erasure requirements?
Not by itself. You must purge all copies within the required window. That includes primary tables backups object storage and search indexes. Keep only the minimal audit metadata allowed by policy.
Q6. How do I test that deleted rows never leak into user views?
Add contract tests at the service boundary. Use database views or ORM global scopes that filter by default. Create a synthetic deleted record and assert that core endpoints and search do not return it.
Further Learning
To master data lifecycle management and reliability patterns:
-
Strengthen your fundamentals with Grokking System Design Fundamentals, which is ideal for beginners who want to understand how patterns like soft delete, caching, and replication interact.
-
Dive deeper into event-driven architecture and state recovery with Grokking Scalable Systems for Interviews, which is perfect for intermediate to advanced engineers preparing for FAANG-level design interviews.
GET YOUR FREE
Coding Questions Catalog
$197

$78
$78