Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Soft Delete

A soft delete marks a row as deleted, usually by setting a deleted_at timestamp or a boolean flag, instead of removing it from the table with a DELETE statement. The row physically stays in the database, so it can be restored, audited, or kept for referential integrity with rows that still reference it through a foreign key, while normal queries filter it out by default.

Most ORMs provide it as a built-in behaviour: Laravel’s Eloquent offers the SoftDeletes trait, which scopes every query to exclude soft-deleted rows unless withTrashed() or onlyTrashed() is used, and Doctrine offers a similar extension. Route model binding and other lookups need to be made aware of this. A route bound to a soft-deleted row’s identifier should generally still resolve to a 404 unless the feature explicitly needs to reach trashed records.

Soft deletes trade storage growth and slightly more complex queries for an audit trail and the ability to undo a mistaken deletion. They do not replace a real backup, and any unique constraint on the table needs to account for the fact that a ‘deleted’ row is still occupying its value.

<?php

    use Illuminate\Database\Eloquent\SoftDeletes;

    class Project extends Model
    {
        use SoftDeletes; // adds a deleted_at column to the query scope

    }

    $project->delete();       // sets deleted_at, row is kept
    Project::withTrashed();   // includes soft-deleted rows
    Project::onlyTrashed();   // only soft-deleted rows

?>

Documentation