eloquage/filament-horizon
A Filament plugin that brings Laravel Horizon into your admin panel, letting you monitor queues, jobs, supervisors, and worker metrics without leaving Filament. Troubleshoot background processing from one dashboard.
Filament Horizon is a Filament plugin that surfaces Laravel Horizon's queue monitoring inside a Filament panel — metrics, recent jobs, pending/completed/failed job lists, and batch views rendered as Filament pages and dashboard widgets.
Prerequisites matter more than the package itself:
php artisan horizon isn't running and horizon:snapshot isn't scheduled, you'll get empty or stale pages.->plugin(FilamentHorizonPlugin::make()) inside Panel::make()->plugins([...])).php artisan filament:optimize (or clear cached components) so the new pages and widgets register.First use case to aim for: a read-only ops panel. Give support/on-call engineers visibility into failed jobs and queue throughput without granting them direct Horizon access (which typically lives behind its own auth gate). Create a dedicated Ops panel or a guard-restricted section of your existing admin panel, register the plugin there, and place the metrics widgets on that panel's dashboard.
Start by opening the Metrics page — if throughput and wait-time charts populate, your Horizon snapshot task is wired correctly and everything else will follow.
Per-panel registration, not global. Register the plugin only on the panels that need it. In multi-panel apps (e.g. Admin for internal staff, App for tenants), you almost never want Horizon pages on a customer-facing panel.
Gate the plugin, don't rely on panel access alone. Use the plugin's authorization hook (a canAccess() / authorize() callback depending on version) to check a policy or Gate — for example Gate::allows('viewHorizon'), or reusing the same callback you pass to Horizon::auth(). This keeps one source of truth between native Horizon and the Filament mirror.
Embed widgets selectively. The metrics widgets are the highest-value, lowest-cost piece. Add the throughput/wait-time widgets to an existing dashboard via the panel's ->widgets([...]) and skip the full pages on panels where operators don't need drill-down. This keeps the nav clean.
Navigation grouping and ordering. Set a custom navigation group (e.g. "Infrastructure") and sort order in the plugin config so Horizon pages don't collide with domain pages. On busy panels, collapse them under a group rather than five top-level items.
Environment scoping. A common pattern is registering the plugin conditionally: full pages in staging/production where Horizon runs, nothing locally where developers use sync or database queues. Wrap registration in if (config('horizon.enabled')) or an environment check.
Localization of the monitoring workflow. Pair the failed-jobs page with your alerting: on-call gets a Slack alert from Horizon's notifier, clicks through to the Filament page (same auth as the admin panel), and retries the job there. Document that URL in your runbook.
Empty pages are almost always a Horizon problem, not a Filament problem. Before debugging the plugin, verify php artisan horizon:status, confirm the horizon:snapshot command is in routes/console.php/kernel schedule running every five minutes, and check REDIS_* env vars. Metrics charts with no data point to a missing snapshot task 90% of the time.
Authorization is opt-in. Filament panel access does not automatically mean Horizon access was intended. If you register the plugin on a broadly accessible panel without a canAccess callback, every panel user sees queue internals — job payloads can contain serialized models and user data. Always gate it.
Long-running workers and stale UI. After deploying new job classes, Horizon needs horizon:terminate (or your deploy script's restart step) before the UI reflects them. If the plugin shows jobs that no longer exist in code, that's the cause — not caching in Filament.
Widgets can be expensive on large queues. The "recent jobs" and failed-jobs widgets hit Redis sorted sets; on high-throughput queues, placing several monitoring widgets on a busy dashboard adds latency to every dashboard load. Prefer the full pages for heavy inspection and keep dashboard widgets to the two metrics charts.
Config caching bites during setup. If pages 404 after install, run php artisan config:clear and php artisan filament:optimize-clear — Filament caches discovered pages/components, and fresh plugin registration won't appear until the cache is rebuilt.
Version pinning across Filament majors. Filament plugins are tightly coupled to Filament's major version; a Filament 3→4 upgrade will likely require a matching plugin release. Pin the plugin version in composer.json and check compatibility before bumping Filament, especially since this is a 1.0.0 line with limited release history.
Route prefix conflicts. The plugin registers routes under the panel's path. If you have a horizon path segment already in use (or a custom Horizon::path()), verify there's no collision; adjust the panel path or plugin slug in config if so.
Extension point to watch: the page and widget classes are ordinary Filament resources/pages — you can subclass them to add columns, filters, or custom actions (e.g. a "retry all failed" bulk action scoped to a tag). Prefer subclassing over forking, so upgrades stay clean.
How can I help you explore Laravel packages today?