Skip to content

Laravel BackfillData backfills you can kill

Safe, resumable, one-off data changes over large tables โ€” keyset paginated, crash-proof, and testable.

Install โ€‹

bash
composer require kstmostofa/laravel-backfill
php artisan migrate

Write one โ€‹

php
class BackfillUserSlugs extends Backfill
{
    public int $batchSize = 1000;

    public function collection(): Builder
    {
        return User::query()->whereNull('slug');
    }

    public function process($record): void
    {
        $record->update(['slug' => Str::slug($record->name)]);
    }
}

Run it โ€‹

bash
php artisan backfill:run user-slugs --dry-run   # scope, index check, real diffs, zero writes
php artisan backfill:run user-slugs             # resumable, killable, throttled

The test behind the claim โ€‹

The promise that you can kill a backfill at any moment is worth exactly as much as the test behind it. So the test does not simulate a crash: it forks, and the child sends itself a real SIGKILL from inside a batch transaction โ€” uncatchable, no destructors, no shutdown handlers. It then asserts the resumed run reaches byte-for-byte the same end state as an uninterrupted control run, with every row processed exactly once.

   PASS  Tests\Chaos\HardKillTest
  โœ“ it resumes after a SIGKILL to the identical end state                1.19s
  โœ“ it leaves no work half-applied when killed inside a batch            1.11s

  Tests:    245 passed (554 assertions)

Green on SQLite, MySQL 8.4 and PostgreSQL 18, with the chaos test running for real on each.

Released under the MIT Licence.