FilamentPHP Table Pagination and Cross-Page Bulk Actions
Filament admin tables paginate server-side, but bulk actions span all pages. Learn to scope, verify, and bound the work.
22 Jun 2026, 16:39 UTC

An admin list that grows faster than your server can load it
You build a FilamentPHP resource for orders. Everything works until the table passes 10,000 rows. A support agent selects 150 rows spread across three pages and runs a bulk archive action. The request hangs. The database slows. The application may attempt to hydrate every selected model before the update even starts.
The useful takeaway is simple: Filament’s Table component paginates queries server-side by default, but a bulk action operates on the rows you select across those pages. If you do not bound the action, you trade pagination efficiency for memory exhaustion.
How Filament Tables paginate
When you place a Table inside a Filament Resource, Filament builds the listing query using Laravel’s paginate(), not get(). The database receives LIMIT and OFFSET bounds, so only the current page’s rows are hydrated for the view.
You can change the available page sizes with paginationSettings():
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginationSettings([10, 25, 50, 100]);
}
Run this in app/Filament/Resources/OrderResource.php (path may differ by installation). You need write access to the project directory; no special database permissions are required to edit the file. The risk is cosmetic: offering very large page sizes can make the table feel slower and hide the current page size from users.
Bulk actions run across pages
Bulk actions are declared in bulkActions(). Filament sends the selected record identifiers to the server, and the action handler receives the matching Eloquent models. Because the selection can span multiple pages, the handler must assume it is working with a subset of the full table, not the entire result set.
Built-in confirmation modals and policy gates apply before the handler executes. Verify that your policy allows the action for the models being selected, especially when soft deletes are enabled; a bulk delete may restore or permanently remove records depending on how the action is configured.
Worked example: archive selected orders
This example adds an archive bulk action to an Order resource. Place the table configuration in your resource class:
use App\Models\Order;
use Filament\Actions\BulkAction;
use Filament\Tables\Table;
public function table(Table $table): Table
{
return $table
->paginationSettings([25, 50])
->bulkActions([
BulkAction::make('archive')
->label('Archive selected orders')
->requiresConfirmation()
->action(function (array $records): void {
foreach ($records as $order) {
$order->update(['status' => 'archived']);
}
}),
]);
}
Where to run: edit the resource file in your Laravel project, then serve the admin panel locally or in staging. Required permissions: filesystem write access to the resource directory. Expected check: open Laravel Debug Bar or your database query log while loading the resource index. You should see a paginated query with LIMIT and OFFSET, not an unbounded SELECT * FROM orders.
Risk: if an agent selects hundreds of rows, the foreach loop updates each model individually and may run longer than the web request timeout. Treat this pattern as safe for small selections only.
Limitation: long-running database work
Bulk actions that update many rows can hold database locks or exceed PHP timeouts. For extensive operations, dispatch a queued job or process records in chunks instead of updating them inline inside the action handler. Soft-deleted records are excluded from table queries by default; confirm whether your bulk action should restore, soft-delete, or force-delete before you enable it.
Check the result before you ship it
- Load the resource index with Debug Bar enabled.
- Confirm the listing query contains
LIMITandOFFSET. - Select rows on page one and page two, then trigger the bulk action.
- Verify only the selected identifiers were updated, and that unselected rows on those pages remain unchanged.
If the action touches state, test it on a copy of production data first. There is no automatic rollback for a bulk update; reverse it by running the inverse update or restoring from a backup.
Closing
FilamentPHP gives you server-side pagination and declarative bulk actions out of the box, but the two features do not automatically bound each other. Use paginationSettings() to control page size, scope bulk actions to the selected records you actually need, and move large updates behind a queue. Verify the generated SQL before you let an administrator select hundreds of rows at once.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.