Laravel Soft delete keeps your data safe by hiding it instead of deleting it. The row stays in your database, just marked with a deleted_at timestamp so Laravel knows to skip it during queries.

It’s a great way to give users a safety net  useful for restoring posts, logs, or anything that shouldn’t be gone forever.

How Laravel Handles Hidden Records

  • Records aren’t removed  they’re just timestamped.
  • The deleted_at column signals Laravel to skip them.
  • Regular queries won’t show soft-deleted data.
  • You can restore or permanently delete anytime.
  • Ideal for user-generated content or sensitive logs.

Behind the Scenes: How Soft Delete Works in Laravel

Laravel handles soft deletion using a trait called SoftDeletes. Instead of wiping the record, it fills in the deleted_at field  simple but effective.

  • Add use SoftDeletes; to your model.
  • When delete() runs, the row stays but gets tagged.
  • Use withTrashed() to include soft-deleted items.
  • onlyTrashed() shows only deleted records.
  • restore() brings the row back to life.

How to Enable Soft Delete in Laravel

// Step 1: Add softDeletes() in your migrationSchema::table(‘posts’, function (Blueprint $table) {

    $table->softDeletes(); // Adds ‘deleted_at’ column

});

 

// Step 2: Run migration

 

php artisan migrate;

 

// Step 3: Use SoftDeletes in your model

 

use Illuminate\Database\Eloquent\SoftDeletes;

 

class Post extends Model

{

    use SoftDeletes;

}

Restoring Soft Deleted Records in Laravel

Need to bring back something that was soft deleted? Laravel makes it easy with the restore() method no complex logic required.

You can recover single or multiple records directly, as long as they haven’t been permanently deleted.

Ways to Restore Soft Deleted Data:

  • Use withTrashed() to fetch both active and deleted records.
  • Call restore() on the model to undo the deletion.

Example:

$post = Post::withTrashed()->find($id);$post->restore();

To restore multiple:

Post::onlyTrashed()->where(‘author_id’, $id)->restore();

Restored data acts like it was never deleted  seamlessly reactivates.

How to Permanently Delete Records in Laravel

Use forceDelete() to remove soft deleted data completely from the database. This action cannot be undone.

$post = Post::withTrashed()->find($id);$post->forceDelete();

This method is useful when you want to free up storage or comply with data removal policies.

How to Check If a Record Was Soft Deleted

To check if a model was soft deleted, use the trashed() method. It returns true when the deleted_at column isn’t null.

$post = Post::withTrashed()->find($id);if ($post->trashed()) {

    // Soft deleted

}

This is useful for toggling restore options or filtering results in admin views.

Also Read: The Laravel Helper Functions

Soft Deletes in Relationships (User → Posts Example)

Soft deletes work across relationships too  but Laravel won’t load deleted children unless you explicitly tell it to. Let’s say you’re building a user profile and want to include their posts, even if some were soft deleted.

Show All (Including Deleted) Related Models

Use withTrashed() inside your relationship query:

$user = User::with([‘posts’ => function ($query) {    $query->withTrashed();}])->find($id);

Now, $user->posts will include both active and soft deleted posts.

Show Only Deleted Posts

Need to work only with soft deleted items? Use onlyTrashed() instead:

$deletedPosts = $user->posts()->onlyTrashed()->get();

This grabs only the posts that were soft deleted  useful for admin dashboards or restore panels.

Restoring Soft Deleted Child Models

You can’t directly restore a whole relationship, but you can loop and restore each soft-deleted record:

$trashedPosts = $user->posts()->onlyTrashed()->get();foreach ($trashedPosts as $post) {

    $post->restore();

}

This brings all deleted posts back to life, one by one.

Real Use Case

If you’re building a “User Restore” feature and you want to also restore everything tied to them (posts, comments, etc.), this approach keeps it clean, safe, and under control  no need for heavy logic or raw queries.

Backend-Only Favorite

82% of developers rely on Laravel strictly for backend development, proving its dominance in powering APIs and server-side logic.

Cascading Soft Deletes in Laravel

When a parent model like User is soft deleted, you may want its related data (like posts) hidden too. Laravel doesn’t handle this by default  use the deleting event to trigger soft deletes on related records.

Example: Soft Deleting Related Records Automatically

// Inside your User modelprotected static function booted()

{

    static::deleting(function ($user) {

        if (! $user->isForceDeleting()) {

            $user->posts()->delete(); // Soft delete related posts

        }

    });

}

This ensures that when you call $user->delete(), all related posts go into the trash too  not just the user.

Be Careful with forceDelete

If you use forceDelete() on the parent, Laravel will still call this deleting hook  so check if it’s a force delete to avoid unnecessary logic:

if (! $user->isForceDeleting()) {    // Only soft delete children if parent is being soft deleted}

Use Cases

  • Deleting a user should soft delete their profile, posts and comments.
  • Removing a blog post might soft delete tags or media tied to it.

This approach gives you clean, logical cascades without writing complex queries manually.

Conclusion

Soft deletes in Laravel offer the perfect balance between safety and flexibility. Whether you’re managing user content, logs, or complex relationships, the built-in tools like SoftDeletes, withTrashed(), and forceDelete() give you full control. 

Use cascading soft deletes for clean data management and always double-check before permanent removal.