Skip to main content

Overview

Soft delete allows you to mark records as deleted without permanently removing them from the database. This is useful for:
  • Maintaining data history
  • Implementing “trash” functionality
  • Audit trails and compliance
  • Recovering accidentally deleted records

Setup

Entity Configuration

Add a deletedAt column to your entity:
user.entity.ts
The @DeleteDateColumn() decorator from TypeORM automatically handles soft delete timestamps.

Controller Configuration

Enable soft delete in your controller:
users.controller.ts

How It Works

When soft delete is enabled:

Delete Operation

Request:
Behavior:
  • Sets deletedAt to current timestamp
  • Record remains in database
  • Record is excluded from normal queries

Query Behavior

By default, soft-deleted records are excluded: Request:
Result:
  • Returns only records where deletedAt IS NULL
  • Soft-deleted records are hidden

Including Deleted Records

Use the includeDeleted query parameter: Request:
Result:
  • Returns all records, including soft-deleted ones
  • Useful for showing “trash” views

Recovery Endpoint

The recoverOne endpoint restores soft-deleted records: Request:
Behavior:
  • Sets deletedAt to null
  • Record becomes visible in normal queries again

Configure Recovery Response

Control whether to return the recovered entity:
users.controller.ts

Global Configuration

Enable soft delete globally for all controllers:
main.ts
Ensure all entities have a deletedAt column before enabling soft delete globally.

Complete Example

Here’s a full implementation:

Entity

company.entity.ts

Controller

companies.controller.ts

Service

companies.service.ts

Usage Examples

Soft Delete a Company

List Active Companies

Returns only companies where deletedAt IS NULL.

List All Companies (Including Deleted)

Returns all companies, including soft-deleted ones.

Filter Deleted Companies Only

Recover a Company

With Relationships

Soft delete works with relationships:
Related entities can also be soft-deleted. Configure each entity independently.

Cascade Soft Delete

To soft delete related entities, configure cascades in your entity:
company.entity.ts

Disabling Specific Routes

You can disable the recover route if not needed:

Swagger Documentation

When soft delete is enabled, Swagger automatically documents:
  • includeDeleted query parameter on getMany and getOne
  • PATCH /:id/recover endpoint for recovery
  • deletedAt field in entity schemas

Hard Delete

To permanently delete records, implement a custom method:
users.controller.ts
users.service.ts

Best Practices

1

Use DeleteDateColumn

Always use TypeORM’s @DeleteDateColumn() decorator for consistency.
2

Index deletedAt

Add an index to deletedAt for better query performance.
3

Audit Trail

Combine with @CreateDateColumn() and @UpdateDateColumn() for complete audit trails.
4

Cleanup Strategy

Implement a cleanup job to hard delete old soft-deleted records if needed.

Database Migration

Add soft delete to existing tables:

Troubleshooting

Records Not Being Soft Deleted

Ensure:
  1. Entity has @DeleteDateColumn() decorator
  2. softDelete: true is set in query options
  3. Service extends TypeOrmCrudService

Deleted Records Still Appearing

Check:
  1. includeDeleted parameter isn’t being set
  2. Query filters aren’t overriding soft delete behavior
  3. Database column exists and is nullable