Guide
Creating a Custom Bulk Action in FilamentPHP Resource Tables
Learn how to add a custom bulk action to a FilamentPHP resource table, with a worked example, limits, and common pitfalls.
Published by Tasadduq Burney
09 Nov 2025, 13:42 UTC
3 min26.4K views0

Useful answer
FilamentPHP lets you add a custom bulk action to a resource table so that clicking a single button runs your code on every selected record.
How a custom bulk action works
The mechanism consists of three steps:
- Create a PHP class that extends
Filament\Tables\Actions\BulkActionand implements theaction()method. - Optionally define
getName(),getLabel()andgetIcon()to control how the button appears. - Register the class in the resource’s
table()method using->bulkActions([...]).
Define the bulk action class
use Filament\Tables\Actions\BulkAction;
use Illuminate\Database\Eloquent\Model;
class MarkAsProcessed extends BulkAction
{
protected function getName(): string
{
return 'mark_as_processed';
}
protected function getLabel(): string
{
return 'Mark as processed';
}
protected function getIcon(): string
{
return 'heroicon-o-check-circle';
}
public function action(array $data): void
{
$ids = $data['selected'];
// Replace `YourModel` with the actual Eloquent model used by the resource.
YourModel::whereIn('id', $ids)->update(['processed' => true]);
notification()->success('Selected items marked as processed.');
}
}
Register the action in the resource
use Filament\Tables\Table;
use App\Filament\Resources\YourResourceResource;
use App\Filament\Actions\MarkAsProcessed;
public function table(Table $table): Table
{
return $table
->columns([
// … your existing columns …
])
->bulkActions([
BulkAction::make('mark_as_processed')
->action(fn (array $data) => app(MarkAsProcessed::class)->action($data)),
]);
}
Limits and considerations
- Bulk actions run synchronously inside the same HTTP request that triggered the button. Processing thousands of rows can exceed PHP memory limits, max execution time, or cause long‑running database locks.
- The action receives only the primary‑key IDs of the selected rows; any additional data must be fetched inside the
action()method. - If the table uses pagination that disables chunking (e.g., custom query builders without simple pagination), the bulk action will only see the rows on the current page.
Common mistakes and how to avoid them
- Forgetting to return a response – the action method must end with a notification, redirect, or similar; otherwise the browser receives an empty response and appears to hang.
- Skipping authorization – without an
authorize()method or a policy, any user who can see the table could mass‑update data. Implementpublic function authorize(): bool { return auth()->user()->can('process', YourModel::class); }or attach a policy via->authorize()on the bulk action definition. - Assuming asynchronous execution – the code runs immediately; for long‑running jobs you should dispatch a queued job inside
action()instead of doing the work directly.
Verifying the bulk action
- Add the class and registration code to a Filament resource in your local development environment.
- Start the dev server with
php artisan serveand log in as a user authorized to perform the action. - Open the resource index page, check several rows, and click the new “Mark as processed” button.
- Look for the success notification and confirm that the
processedcolumn is set totruefor the selected rows in the database. - Optionally tail the Laravel logs (
tail -f storage/logs/laravel.log) or enable Laravel Debugbar to see that theaction()method was invoked and no exceptions were thrown.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.