Reader Stacks

How to Fetch (and Restore) Soft-Deleted Records in Laravel

withTrashed(), onlyTrashed(), and restore() — plus the query-scope gotcha that makes soft-deleted rows silently vanish from relationships by default.

How to Fetch (and Restore) Soft-Deleted Records in Laravel

Soft deletes (the SoftDeletes trait) don't actually remove a row — they set a deleted_at timestamp and Eloquent silently excludes it from normal queries. That silence is the whole feature, and also the thing people trip over.

Including soft-deleted rows: withTrashed()

$allUsers = User::withTrashed()->get(); // includes soft-deleted rows

Only the soft-deleted rows: onlyTrashed()

$deletedUsers = User::onlyTrashed()->get();

Restoring a soft-deleted row

$user = User::onlyTrashed()->find($id);
$user->restore();

Or in one line:

User::onlyTrashed()->where('id', $id)->restore();

Permanently deleting it

User::onlyTrashed()->where('id', $id)->forceDelete();

The relationship gotcha

This is the part that causes real bugs: a soft-deleted parent's related rows don't show up through a normal relationship query either, because the relationship query goes through the same SoftDeletes global scope.

// A post's soft-deleted comments are invisible here by default:
$post->comments;

// Include them explicitly:
$post->comments()->withTrashed()->get();

This matters most for withCount() and eager-loading: a count that silently excludes soft-deleted related rows can look like a data bug when it's actually the intended behavior — just not the behavior you expected in that specific query.

Topics: Database Queries & Eloquent