Laravel cookbook · Beginner

Delete old records automatically with prunable models

Tables of logs, sessions and soft-deleted rows grow forever.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Implement Prunable (or MassPrunable for speed) with a query for rows to delete, clean up related files in pruning(), and schedule model:prune.

Solution

<?php
// app/Models/ActivityLog.php
namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\MassPrunable;
use Illuminate\Database\Eloquent\Model;

class ActivityLog extends Model
{
    use MassPrunable;                                  // one DELETE per chunk, no model events

    public function prunable(): Builder
    {
        return static::where('created_at', '<', now()->subDays(90));
    }
}
<?php
// app/Models/Export.php
namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;
use Illuminate\Support\Facades\Storage;

class Export extends Model
{
    use Prunable;

    public function prunable(): Builder
    {
        return static::where('created_at', '<', now()->subWeek());
    }

    protected function pruning(): void
    {
        Storage::disk('s3')->delete($this->path);       // runs for each model before deletion
    }
}

Pitfalls

  • Forgetting to schedule model:prune, so nothing is ever deleted.
  • Using MassPrunable when files or related records must be cleaned up (it skips pruning()).
  • Retention periods that conflict with legal requirements; agree on them with the business.

Variations

  • Run php artisan model:prune --pretend to see how many rows would be deleted.
  • Soft-deleted models can be pruned with static::onlyTrashed()->where(...).

Further reading: Pruning models

Reference: https://laravel.com/docs/13.x/eloquent#pruning-models

More Laravel recipes

Was this page helpful?