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:
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:
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.