[ GUIDE ]

Monitoring Laravel Filament

Filament is a Laravel app with Livewire under the hood — but admin panels have their own performance footguns worth watching for.

QUICK ANSWER

How do I monitor a Laravel Filament admin panel?

Filament is a Laravel app, so standard Laravel monitoring works. Filter your APM to /admin/* (or your panel's prefix) to isolate admin traffic from public. Watch for the classic bugs: unoptimized table resources with lazy-loaded relationship columns, widget queries that don't cache, and dashboards that render hundreds of data points. Track failed admin logins as a security signal. NightOwl records every /admin request and Livewire update — Filament-specific resource grouping is on the roadmap.

Updated · 2026-06-06

Filament gives you a production admin panel in an afternoon, which is exactly why its performance problems sneak up on you. Nobody profiles the admin — it's internal, it's for staff, it feels instant on a dev machine with fifty seed rows. Then the users table hits a hundred thousand rows, a relationship column lazy-loads on every one of them, and the page that used to open instantly takes eight seconds and times out for the one admin who filters by company. The panel is a Laravel app underneath, so the fixes are ordinary Laravel fixes — you just have to be looking at it.

Table resources — the biggest performance trap

A Filament Resource renders a Livewire-powered table. Each column is a template expression; relationship columns lazy-load their relations on access:

Bad — fires N queries per page load

php
class UserResource extends Resource
{
    public static function table(Table $table): Table
    {
        return $table->columns([
            TextColumn::make('name'),
            TextColumn::make('latestOrder.total'),    // N+1
            TextColumn::make('company.name'),         // N+1
            TextColumn::make('subscription.plan'),    // N+1
        ]);
    }
}

Good — eager-load in getTableQuery

php
class UserResource extends Resource
{
    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with(['latestOrder', 'company', 'subscription']);
    }
}

For complex tables with counts, use withCount() instead of computing in the view. Aggregate columns should be SQL-side whenever possible.

Widget caching

Filament widgets re-render on page load and on ->poll() interval. Uncached queries run every time:

php
class TotalRevenueWidget extends StatsOverviewWidget
{
    protected static ?string $pollingInterval = '30s';

    protected function getStats(): array
    {
        // Bad — hits DB every 30s
        // $total = Order::where('paid', true)->sum('total');

        // Good — cached
        $total = Cache::remember('stats.total_revenue', 30, fn () =>
            Order::where('paid', true)->sum('total')
        );

        return [
            Stat::make('Revenue', '$' . number_format($total, 2)),
        ];
    }
}

Admin auth failure tracking

/admin is a high-value target for attackers. Track failed logins:

app/Providers/AppServiceProvider.php

php
use Illuminate\Auth\Events\Failed;
use Illuminate\Support\Facades\Event;

Event::listen(function (Failed $event) {
    if (str_contains(request()->path(), 'admin')) {
        logger()->warning('Admin login failure', [
            'email' => $event->credentials['email'] ?? null,
            'ip' => request()->ip(),
            'ua' => request()->userAgent(),
        ]);
    }
});

Alert on failed-login rate spikes per IP. Combine with Laravel's built-in throttling and ideally IP-allowlisting at the load balancer.

What to track per resource

  • List page load — should be < 400ms p95 for admin usability
  • Row actions — edit / delete / bulk. Target < 300ms per Livewire update.
  • Form submit — complex forms with many fields can be slow on save. Profile the Resource model's save() path.
  • Bulk actions — users expect these to be reasonably fast. If bulk is slow (> 2s for 50 rows), queue them instead.

Filtering your APM to admin traffic

In most APMs, filter requests by URL prefix:

  • /admin/* — panel page loads, form submits
  • /livewire/update — table filters, actions, form field updates
  • /admin/login — auth attempts

THE EASY WAY

Catch Filament bottlenecks with per-request tracing

NightOwl records every /admin request with full trace breakdown — see which Livewire update fired 340 DB queries, which table resource loaded 50 MB of eager-loaded relations. The request drilldown turns Filament slowness from guesswork into a one-line fix.

bash
composer require nightowl/agent
php artisan nightowl:install

Frequently asked questions

Does Filament need its own monitoring setup?

Not technically — it's a Laravel app that ships Livewire components. Regular Laravel monitoring + Livewire-aware patterns covers it. But Filament admin panels have specific performance footguns (large table resources, unoptimized relationship columns, heavy dashboards) that deserve attention separately from the public-facing app.

What's the most common Filament performance bug?

Unoptimized table resources. A Filament Resource renders a Livewire component; the table fires a COUNT query plus a SELECT per page. With relationships displayed as columns, each row triggers a lazy-load unless the query is eager-loaded. Override getTableQuery() and add ->with([...]) for every relationship column shown.

How do I monitor Filament admin panel usage?

Filament routes are prefixed (usually /admin/*). Filter your APM to /admin/* to see admin-only traffic separately from public. Track per-resource slow operations: loads, updates, bulk actions. For user auditing (who did what in the admin), Filament's own activity logging plugin or spatie/laravel-activitylog covers it — that's operational auditing, not performance monitoring.

Should I run Filament behind auth in production monitoring?

Yes. /admin is a high-value target. Enforce strict auth (2FA preferred), IP-allowlist if possible, and monitor authentication failures — spikes in failed logins indicate credential stuffing or brute force. Laravel's built-in login throttling helps but isn't sufficient by itself.

How do I speed up slow Filament dashboards?

Three wins. First, cache widget data — Filament's Widget::make()->poll() re-fetches on a timer; use Cache::remember() inside to avoid hitting the DB every refresh. Second, limit chart data ranges — rendering 365 days of hourly data is 8,760 data points. Third, for multi-table dashboards, fire queries in parallel via Http::pool() or Laravel 11's Process::concurrently where applicable.

What about Filament v4 vs v3 for monitoring?

v4 (2026) changed the JS layer and some Livewire integration points but kept the Resource / Widget / Form model. Monitoring concerns are the same — the bottlenecks are still table queries, widget computations, and form validation. v4's schema-based forms can hide N+1 in computed fields the same way v3 did; watch for lazy-loaded relationship access in form lifecycle hooks.

Does NightOwl have Filament-specific dashboards?

Not as a first-class feature. Filament shows up as normal Laravel requests (/admin/*) and Livewire updates (/livewire/update). You filter by URL prefix to isolate admin traffic. A Filament-aware resource breakdown is on the roadmap but not shipping today.

PRICING

Flat pricing. No event caps. No per-seat fees.

14-day free trial, no credit card. Your PostgreSQL, your data.

HOBBY

$5 /month

1 app · 14 days lookback · all Laravel events

TEAM

$15 /month

Up to 3 connected apps · unlimited environments · all Laravel events

AGENCY

$69 /month

Unlimited apps · unlimited agent instances · same flat rate at any traffic

Related