Implementing Efficient Bulk Update Actions in FilamentPHP Resources
Learn how to create a mass‑update bulk action that safely modifies multiple Eloquent records inside a Filament admin table, with considerations for performance, authorization, and verification.
04 Jul 2026, 23:15 UTC

Problem: Updating many records one‑by‑one is tedious
When managing content in a Filament admin panel, administrators often need to apply the same change to dozens or hundreds of rows—for example, publishing a batch of draft posts or marking invoices as paid. Doing this manually through individual edit forms is error‑prone and time‑consuming.
Thesis: A custom bulk action gives you a reusable, transaction‑safe way to run mass updates while keeping Filament’s built‑in validation and feedback.
By extending Filament\Tables\Actions\BulkAction and implementing its handle method, you receive a collection of the selected models, can wrap the changes in a database transaction, and let Filament handle authorization checks, notifications, and UI updates.
1. Defining the bulk action class
Run the following Artisan command in your project root (you need write access to the app/Filament/Actions directory):
php artisan make:filament-action PublishPosts --bulk
This creates app/Filament/Actions/PublishPosts.php with a stub that already extends BulkAction. Replace the generated handle method with the logic below:
use Filament\Tables\Actions\BulkAction;
use Illuminate\Support\Collection;
use App\Models\Post;
class PublishPosts extends BulkAction
{
protected function getAction(): string
{
return 'publish';
}
protected function getLabel(): string
{
return 'Publish selected posts';
}
public function handle(Collection $records): void
{
// Wrap the whole operation in a transaction so either all succeed or none.
DB::transaction(function () use ($records) {
foreach ($records as $post) {
/** @var Post $post */
$post->update([
'published_at' => now(),
'status' => 'published',
]);
}
});
}
}
Where to run: local development environment or any server with PHP ≥ 8.1 and Composer installed. Required permissions: ability to execute Artisan commands and write to the app/Filament/Actions folder.
2. Attaching the action to a resource table
Open the resource class for the model you want to act on (e.g., app/Filament/Resources/PostResource.php) and add the action to the bulkActions method:
use Filament\Resources\Resource;
use Filament\Tables\Table;
use App\Filament\Actions\PublishPosts;
class PostResource extends Resource
{
public static function table(Table $table): Table
{
return $table
->columns([
// … existing columns …
])
->bulkActions([
PublishPosts::make(),
]);
}
}
After saving, clear the view cache if needed (php artisan view:clear) and navigate to the Post index in the Filament admin. When you select one or more checkboxes, a dropdown appears in the table header containing “Publish selected posts”.
3. Worked example: publishing three draft posts
- In the Posts index, tick the checkboxes for posts with IDs 12, 15, and 23.
- Open the bulk‑action dropdown and choose “Publish selected posts”.
- Filament sends a POST request to the action endpoint, instantiates
PublishPosts, and callshandlewith aCollectioncontaining the threePostmodels. - The
handlemethod opens a transaction, loops through each model, callsupdateto setpublished_atandstatus, then commits. - Filament shows a success toast (“3 posts published”) and refreshes the table rows so the updated values are visible.
Expected checks: after the action finishes, you can verify the changes directly in the database:
SELECT id, published_at, status FROM posts WHERE id IN (12,15,23);
You should see a non‑null published_at and status = 'published' for each row.
Trade‑off: Performance and side‑effects
While bulk actions are convenient, they process all selected records in a single request. If a user selects thousands of rows:
- Memory usage can spike because the entire
Collectionis loaded. - PHP’s max execution time (
max_execution_time) may be exceeded. - Model events such as
saving,saved, or observer listeners are not triggered by theupdatecall unless you explicitly fire them.
Limitation checklist:
- Large datasets – consider chunking the collection or dispatching a queued job inside
handle. - Granular authorization – Filament checks permission on the action class only; you must add a manual
if (! $post->canPublish()) { … }check inside the loop if needed. - Event listeners – if your application relies on observers for side effects (e.g., clearing caches), call
$post->save()instead ofupdateor manually dispatch the events.
Practical way to check the result: after running the bulk action on a small test set (e.g., 5 records), run the verification query above and also inspect your logs for any queued jobs or exceptions. If the table updates correctly and no errors appear, the action is behaving as expected.
Actionable closing
Start by generating a bulk‑action stub with Artisan, implement the handle method using a transaction, and attach it to your resource’s bulkActions. Test with a handful of records, verify the DB changes, and then consider adding chunking or queuing if you anticipate larger batches. This approach gives you a clean, reusable pattern for mass updates while keeping Filament’s safety nets intact.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.