Implementing Safe Bulk Deletion in FilamentPHP Resource Tables
Learn how to implement a safe bulk delete feature in FilamentPHP using SoftDeletes, confirmation modals, and Eloquent event handling to manage large datasets efficiently.
26 Jul 2026, 19:31 UTC

The Challenge of Mass Record Management
Managing large datasets in an admin panel often requires the ability to remove multiple records simultaneously. Without a configured bulk action, administrators must delete records one by one, which is inefficient and prone to user fatigue. The goal is to implement a bulk delete mechanism that provides a safety confirmation modal and integrates with Laravel's soft delete functionality to prevent permanent data loss.
Prerequisites
- A Laravel project with FilamentPHP installed and configured.
- A Filament Resource class (e.g.,
UserResource) extendingFilament\\Resources\\Resource. - A Model that uses the
Illuminate\\Database\\Eloquent\\SoftDeletestrait to ensure records are flagged as deleted rather than purged from the database.
Configuring the Bulk Delete Action
Filament handles bulk actions within the table() method of your Resource class. To implement a safe deletion process, you must define a BulkAction that iterates through the selected record collection.
Implementation Example
Add the following configuration to your Resource's table method. This example assumes you are working within a UserResource class:
use Filament\\Tables\\Actions\\BulkAction;
use Illuminate\\Database\\Eloquent\\Collection;
public static function table(Table $table): Table
{
return $table
->columns([
// Your columns here
])
->bulkActions([
BulkAction::make('delete_selected')
->label('Delete Selected')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->action(fn (Collection $records) => $records->each->delete()),
]);
}
Engineering Decisions: Performance vs. Events
The choice of how to execute the deletion impacts both performance and application logic. There are two primary patterns for the action() closure:
| Method | Execution | Model Events | Performance |
|---|---|---|---|
$records->each->delete() |
Iterative | Fires deleting and deleted events per model. |
Slower for very large sets. |
$records->delete() |
Query-based | Bypasses Eloquent model events. | Faster (single SQL query). |
Recommendation: Use $records->each->delete() if you have observers or model events that must trigger (e.g., deleting related files from S3). Use the direct query method only for high-volume tables where event triggering is unnecessary.
Security and Authorization
Bulk actions are powerful and potentially destructive. Filament checks the resource's general authorization, but you should ensure your Laravel Policy explicitly allows the delete ability for the authenticated user.
If you need a custom check specifically for bulk operations, you can chain the visible() method to the action:
BulkAction::make('delete_selected')
->visible(fn () => auth()->user()->hasRole('super_admin'))
Verification and Testing
To verify the implementation, perform the following steps in your local environment:
- Navigate to the Resource index page in the browser.
- Select multiple checkboxes in the table rows.
- Click the "Delete Selected" action in the bulk menu.
- Confirm the action in the modal.
- Database Check: Run the following SQL command to verify that records were soft‑deleted (the
deleted_atcolumn should be populated) rather than hard‑deleted:SELECT * FROM users WHERE deleted_at IS NOT NULL;
Recovery Options
Because this implementation uses SoftDeletes, records can be restored. To provide a recovery mechanism within the UI, you can create a separate bulk action for restoration:
BulkAction::make('restore')
->label('Restore Selected')
->action(fn (Collection $records) => $records->each->restore())
->visible(fn () => request()->query('tableFilters.trashed') === '1')
If you need to recover a record manually via the CLI, use Laravel Tinker:
// Run: php artisan tinker
\\App\\Models\\User::withTrashed()->find(<id>)->restore();
Rollback Procedure
To disable the bulk delete functionality and prevent accidental data loss during a deployment, remove the BulkAction::make('delete_selected') block from the bulkActions() array in your Resource class and redeploy the code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.