Stop N+1 Queries in Filament v3 Tables with Relationship Columns
Prevent N+1 queries in Filament v3 admin tables by eager-loading dot-notation relationship columns.
25 Feb 2026, 07:04 UTC

The problem: one query per row in an admin table
You add a Filament v3 table column that shows a relationship, such as the author of a blog post:
TextColumn::make('author.name')
Dot notation tells Filament to read the author relationship from each post and display name. On your local machine with a few records, the page feels instant. In production, with hundreds of posts, the same page slows to a crawl.
The cause is the classic N+1 query pattern. Filament runs one query to fetch the posts, then Laravel lazy-loads the author relationship separately for every row. If you display 50 posts, you get 51 queries. The table works, but it does not scale.
What to do: eager-load the relationship in the table query
Filament v3 tables expose an eagerLoading() method. It tells the underlying Eloquent query to preload listed relationships before the table iterates over rows. With eager loading, Laravel fetches all authors in a single additional query instead of one per post.
Assuming you are using Filament v3 and a Post resource, add the relationship to the table configuration. Replace Post and author with your own model and relationship name:
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('title'),
TextColumn::make('author.name'),
])
->query(fn (): Builder => Post::query())
->eagerLoading(['author']);
}
The eagerLoading(['author']) call maps to Eloquent's with(), so the generated SQL roughly becomes two queries instead of many:
select * from `posts`;
select * from `users` where `users`.`id` in (1, 2, 3, ...);
Check your installed major version first. Filament v2 and v3 use different table APIs, so confirm filament/filament in composer.json before applying this pattern.
Worked example: verifying the fix
To confirm the change actually removes the N+1 behavior, use a query profiler in a non-production environment.
- Run this in your project root:
composer require --dev barryvdh/laravel-debugbar
No root or sudo permissions are required. Laravel's package discovery usually registers the Debugbar service provider automatically. Keep Debugbar out of production by gating it behind APP_DEBUG or removing it before deployment.
- Seed enough data to expose the problem:
\App\Models\User::factory()->count(10)->create();
\App\Models\Post::factory()->count(50)->create();
Open the Filament list page and open the Debugbar. Before eagerLoading(), expect the query count to rise as you add more posts. After adding eagerLoading(['author']), the query count should stay flat—typically two queries regardless of whether the table shows 10, 50, or 100 posts.
A stricter check is a feature test that asserts query count does not grow with the number of related rows. That test protects the table from future regressions if someone removes the eager-loading call.
Limitation: sorting and filtering still need care
Eager loading fixes the read path, but it does not automatically optimize sorting or filtering on relationship columns. If you make author.name sortable, Filament may attempt to order by the related table. Depending on your database and indexes, that can produce a join or a subquery that is slower than expected.
For complex relationship sorting, consider a custom query scope or an explicit join instead of relying on dot notation alone. Also, eager loading adds memory overhead because related models are hydrated up front. Keep pagination enabled and avoid eager-loading deep relationship chains you do not display.
Rollback and closing
Because this change only modifies PHP configuration, rollback means removing the eagerLoading() line and redeploying. There is no database migration to reverse.
Dot-notation columns are convenient, but they are not free. Pair TextColumn::make('author.name') with eagerLoading(['author']), verify with Debugbar or Telescope, and treat relationship sorting as a separate performance concern. Your admin table will stay fast as your data grows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.