Filament v4 Multi-Panel Auth &amp; Table Query Tuning | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Filament v4 at Scale: Multi-Panel Auth, Custom Panels, and Table Query Tuning

 Filament v4 at Scale: Multi-Panel Auth, Custom Panels, and Table Query Tuning
==============================================================================

 Running Filament v4 across multiple panels with distinct auth guards and thousands of rows? This guide covers custom panel registration, per-panel authentication, and practical table query tuning to keep response times tight.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 13 Sep 2026 · Updated 13 Sep 2026 · 3 min read

ShareCopy linkCopied

 ![Filament v4 at Scale: Multi-Panel Auth, Custom Panels, and Table Query Tuning](https://cdn.msaied.com/664/be327447c5231a3cb27a5df9597890dd.png) 

  On this page +1. [The Problem With One Panel Fits All](#the-problem-with-one-panel-fits-all)
2. [Registering Multiple Panels](#registering-multiple-panels)
3. [Per-Panel Authentication Guards](#per-panel-authentication-guards)
4. [Middleware Isolation](#middleware-isolation)
5. [Table Query Tuning](#table-query-tuning)
6. [Scoped Default Query](#scoped-default-query)
7. [Deferring Expensive Counts](#deferring-expensive-counts)
8. [Column-Level Eager Loading](#column-level-eager-loading)
9. [Takeaways](#takeaways)

 The Problem With One Panel Fits All
-----------------------------------

Most Filament tutorials assume a single `/admin` panel. Real SaaS products need at least two: one for customers, one for internal staff — each with its own auth guard, middleware stack, and resource set. Filament v4's `PanelProvider` architecture makes this clean, but there are sharp edges around query performance once you push table row counts past a few thousand.

This article covers three concrete areas:

1. Registering and isolating multiple panels
2. Wiring per-panel authentication guards
3. Tuning table queries so Filament doesn't become your slowest endpoint

---

Registering Multiple Panels
---------------------------

Each panel gets its own `PanelProvider`. Create two:

```bash
php artisan make:filament-panel customer
php artisan make:filament-panel staff

```

This generates `app/Providers/Filament/CustomerPanelProvider.php` and `StaffPanelProvider.php`. Register both in `bootstrap/providers.php`:

```php
return [
    App\Providers\Filament\CustomerPanelProvider::class,
    App\Providers\Filament\StaffPanelProvider::class,
];

```

Each provider calls `Panel::make()` with a unique ID and path:

```php
public function panel(Panel $panel): Panel
{
    return $panel
        ->id('customer')
        ->path('portal')
        ->login()
        ->resources([
            App\Filament\Customer\Resources\OrderResource::class,
        ]);
}

```

---

Per-Panel Authentication Guards
-------------------------------

Filament v4 exposes `->authGuard()` on the panel builder. Pair it with a dedicated guard in `config/auth.php`:

```php
// config/auth.php
'guards' => [
    'customer' => [
        'driver'   => 'session',
        'provider' => 'customers',
    ],
    'staff' => [
        'driver'   => 'session',
        'provider' => 'staff',
    ],
],
'providers' => [
    'customers' => ['driver' => 'eloquent', 'model' => App\Models\Customer::class],
    'staff'     => ['driver' => 'eloquent', 'model' => App\Models\StaffUser::class],
],

```

Then in each panel provider:

```php
return $panel
    ->id('customer')
    ->path('portal')
    ->authGuard('customer')
    ->login(CustomerLoginPage::class);

```

Filament will resolve `Auth::guard('customer')` for all authorization checks inside that panel. Sessions are fully isolated — a customer cookie never authenticates a staff request.

### Middleware Isolation

Add panel-specific middleware to avoid leaking staff-only rate limits or audit logging into the customer panel:

```php
->middleware([
    EncryptCookies::class,
    StartSession::class,
    App\Http\Middleware\LogCustomerActivity::class,
])
->authMiddleware([
    Authenticate::class,
])

```

---

Table Query Tuning
------------------

Filament's `Table` component calls `->query()` on every page load. The default is `Model::query()` — no eager loads, no scopes. At scale that's a disaster.

### Scoped Default Query

Always scope to the authenticated tenant and eager-load relations the table columns touch:

```php
public static function getEloquentQuery(): Builder
{
    return parent::getEloquentQuery()
        ->with(['customer', 'items.product'])
        ->where('tenant_id', Filament::getTenant()?->id)
        ->withoutGlobalScope(SoftDeletingScope::class);
}

```

### Deferring Expensive Counts

Filament renders a row count badge by default. On large tables this fires a `COUNT(*)` on every render. Disable it when the table is filtered by default and the count is meaningless:

```php
Table::make()
    ->paginated([25, 50, 100])
    ->paginationPageOptions([25, 50])
    ->defaultPaginationPageOption(25)
    ->extremePaginationLinks(false)
    ->queryStringIdentifier('orders')

```

For the count itself, override `getTableRecordsPerPageSelectOptions` or use a database view with a materialized count column rather than a live aggregate.

### Column-Level Eager Loading

Filament v4 columns support `->relationship()` declarations. Use them so the table builder can batch-load only what's rendered:

```php
TextColumn::make('customer.name')
    ->label('Customer')
    ->searchable(query: fn (Builder $q, string $s) =>
        $q->whereHas('customer', fn ($q) => $q->where('name', 'like', "%{$s}%"))
    ),

```

Avoid `->getStateUsing()` callbacks that hit the database per row — they bypass Eloquent's eager loading entirely.

---

Takeaways
---------

- Register each panel in its own `PanelProvider`; use `->authGuard()` to fully isolate sessions.
- Scope `getEloquentQuery()` to the tenant and eager-load every relation the table touches.
- Disable or defer row counts on large tables; a live `COUNT(*)` on 500k rows is expensive.
- Keep panel-specific middleware in the panel provider, not in global `app/Http/Kernel.php`.
- Use `->relationship()` on columns so Filament can batch-load relations rather than resolving them per row.

- [filament](https://www.msaied.com/public/articles?search=filament)
- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [multi-panel](https://www.msaied.com/public/articles?search=multi-panel)
- [performance](https://www.msaied.com/public/articles?search=performance)

 Frequently asked questions 
---------------------------

  Can two Filament v4 panels share the same Eloquent model but use different guards?Yes. Guards are independent of models. You can point two guards at the same `User` model with different session drivers or providers, then assign each guard to a separate panel via `-&gt;authGuard()`. Sessions remain isolated because Filament resolves auth through the panel's configured guard, not the default `web` guard.

   How do I prevent N+1 queries in Filament table columns that use -&gt;relationship()?Override `getEloquentQuery()` in your resource and call `-&gt;with(\[...\])` for every relation your columns reference. Filament does not auto-detect required eager loads from column definitions, so explicit `with()` calls in the base query are the most reliable approach.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleMacros, Mixins, and Custom Collection Methods in Laravel](https://www.msaied.com/public/articles/macros-mixins-and-custom-collection-methods-in-laravel-2) [Next articlePartial Indexes and Covering Indexes in PostgreSQL: A Laravel Developer's Guide](https://www.msaied.com/public/articles/partial-indexes-and-covering-indexes-in-postgresql-a-laravel-developers-guide-1)  

   On this page
-------------

1. [The Problem With One Panel Fits All](#the-problem-with-one-panel-fits-all)
2. [Registering Multiple Panels](#registering-multiple-panels)
3. [Per-Panel Authentication Guards](#per-panel-authentication-guards)
4. [Middleware Isolation](#middleware-isolation)
5. [Table Query Tuning](#table-query-tuning)
6. [Scoped Default Query](#scoped-default-query)
7. [Deferring Expensive Counts](#deferring-expensive-counts)
8. [Column-Level Eager Loading](#column-level-eager-loading)
9. [Takeaways](#takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
