Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Horizon Laravel Package

genealabs/nova-horizon

A Laravel Nova integration for Horizon that brings queue and worker monitoring into your Nova dashboard, letting you view supervisors, jobs, and workload metrics without leaving the admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm both halves are actually running before you touch composer. This package is glue between Nova and Horizon and does nothing on its own:

php artisan horizon:status        # must say "running"
php artisan nova:check            # or just hit /nova
php artisan --version             # Nova 4.x expected

If /horizon doesn't load and show live metrics, stop. Fix Horizon first — an empty Nova tool on top of a broken Horizon is two problems, not one.

Install pinned to the Nova 4 fix:

composer require genealabs/nova-horizon:^0.6.1

Read the source before you register it. It's small — ten minutes end to end — and what you find determines your risk profile:

ls -R vendor/genealabs/nova-horizon/src

You're looking for one of two shapes:

  • Iframe of /horizon — you inherit CSP, X-Frame-Options, and same-origin session assumptions.
  • Re-hosted assets or direct data pulls — you inherit Horizon's compiled front-end output, which shifts on Horizon minors.

Also grep for viewHorizon:

grep -r "viewHorizon" vendor/genealabs/nova-horizon/src

If it's absent, the tool is not consulting Horizon's gate. That's a decision you make deliberately, not a detail you discover during an incident.

Register in tools(), never dashboards():

// app/Providers/NovaServiceProvider.php
use GeneaLabs\NovaHorizon\NovaHorizon; // confirm namespace against vendor/

public function tools()
{
    return [
        NovaHorizon::make(),
    ];
}

Then php artisan package:discover if auto-discovery didn't fire, and a hard refresh.

Local dev caveat. Horizon needs Redis. Set QUEUE_CONNECTION=redis, run php artisan horizon, push a job through, confirm the metric cards populate. If you develop on database queues, install Horizon locally first, then this tool — otherwise you'll spend an hour debugging a page that was never going to work.

First use case: the deploy-day "did the queue drain?" check. In one terminal:

php artisan queue:monitor default:100

Open the Nova tool in another. If queue depth and failure counts agree, the wiring is correct and you can hand it to a non-engineer. If they disagree, suspect a stale Horizon snapshot before suspecting the package.

First real workflow — failed-job triage. Filter to failed jobs in the Nova tool, read the payload and tags, then jump to /horizon/failed/{uuid} for the full trace and retry. Nova is the entry point; Horizon is the deep dive.

Implementation Patterns

Make Nova visibility a subset of Horizon's gate. Two independent authorization systems, one exposure surface:

use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;

public function tools()
{
    return [
        NovaHorizon::make()
            ->canSee(fn (Request $request) => Gate::check(
                'viewHorizon',
                [$request->user()]
            )),
    ];
}

Test with a non-admin Nova account before rollout. If a support user can see failed-job payloads and stack traces through Nova that they'd be blocked from at /horizon, that's a silent privilege escalation, not a UX bug.

Two-tier audience, encoded explicitly. The whole point of adopting this is broadening who can see queue health — so decide who sees what:

  • Engineers — full tool: workers, supervisors, wait times, payload inspection.
  • Support/ops — queue depth, oldest job age, failed count, and a copy-pasteable response ("your export is queued behind N jobs"). If the package can't express that granularity, gate the whole tool to support supervisors and have them relay.

Feature-flag the rollout for the first sprint. Rollback is one line, no schema, no data:

public function tools()
{
    if (! config('app.horizon_tool_enabled')) {
        return [];
    }

    return [
        NovaHorizon::make()
            ->canSee(fn ($request) => Gate::check('viewHorizon', [$request->user()])),
    ];
}
// config/app.php
'horizon_tool_enabled' => env('HORIZON_TOOL_ENABLED', false),

Fold it into the release gate. After every deploy that touches queue code:

  1. Push the deploy.
  2. Open the Nova tool.
  3. Confirm queue depth returns to baseline within the normal window.
  4. Confirm zero new failures in the last 15 minutes.

The value here is entirely that someone who did not write the code can run it.

Keep /horizon reachable and bookmarked. Wire the Nova tool into your incident runbook as the entry point, not the replacement. If the package breaks on an upgrade, team behavior doesn't have to change.

Cross-check against the CLI when you suspect drift:

php artisan horizon:status
php artisan queue:monitor default:100
php artisan horizon:list   # if available in your Horizon version

If the Nova tool and the CLI disagree, you're looking at staleness or an unscheduled snapshot — not a broken package.

Local test harness. A small seeder that dispatches a failing job plus a slow job gives you a reproducible page to verify against:

// database/seeders/HorizonDemoSeeder.php
dispatch(fn () => throw new \RuntimeException('demo failure'));

Run php artisan horizon, seed, then confirm both the failed count and the throughput chart move. Do this once per Nova major upgrade.

Make it the support-facing answer for async features. If exports, imports, report generation, or webhooks are on the roadmap, surface the batch ID in your support UI and let this tool answer "where is my export?" That's the deflection payoff — but only if the failure data is fresh (see Gotchas).

Gotchas and Tips

Metrics need horizon:snapshot on a schedule. If the cards show zeros or gaps while failed jobs populate fine, this is almost always the cause. Check app/Console/Kernel.php (or Laravel 11's routes/console.php):

protected function schedule(Schedule $schedule)
{
    $schedule->command('horizon:snapshot')->everyFiveMinutes();
}

The single most common "the package is broken" false alarm.

Metrics are a rolling window, not history. Horizon keeps short-lived metrics (typically ~24h) and trims. Do not use this to answer "how did the queue perform last Tuesday." Pair with Sentry/Bugsnag/Oh Dear/APM for alerting, SLOs, and retention. This is a dashboard, not a monitoring product.

Empty tool page, no error — debug top-down:

  1. Does /horizon itself load?
  2. Does Gate::allows('viewHorizon') return true for this user?
  3. Is the tool in tools() and not dashboards()?
  4. Is the provider registered (php artisan package:discover)?
  5. Has Nova's asset cache gone stale? php artisan nova:publish and hard refresh.

Nine times out of ten it's canSee or a stale Nova cache.

X-Frame-Options / CSP if it's an iframe. Same host is usually fine. Behind a proxy, on a subdomain, or with a strict frame-ancestors policy, the iframe silently refuses to render. Open devtools and watch for the violation, then either relax the policy for that path or accept the tool is engineer-only on a separate URL.

Pin three versions together, not one. The set that matters is Nova major/minor, Horizon minor, and this package. 0.6.1 narrows the envelope to Nova 4 known-good. Record that in your dependency inventory so the next developer doesn't assume Nova 5 coverage. Never force resolution with --ignore-platform-reqs.

Redis-only, and it inherits that constraint silently. If you run SQS or database queues anywhere in the estate, this tool shows Horizon's Redis queues and nothing else. Label it clearly in those environments or don't deploy it there — a misleading picture that people trust is worse than no picture.

Treat it as vendored glue. Ten stars, zero dependents, single maintainer — but the codebase is small enough that forking is hours, not days. 0.6.1 arriving as a community-contributed Nova 4 fix is evidence that narrow reactive patches land upstream. That's your extension point: read the source, keep a fork branch in your org, and budget a half-day for adoption with that in mind.

Watch audience scaling cost. Each viewer adds Horizon Redis polling plus a Nova asset bootstrap. A handful of operators is free; opening it to the entire CS org is not. If the audience grows, consider a cached read-only snapshot instead.

Evaluate Pulse before committing. On Laravel 11+, first-party Pulse covers queue throughput and failure visibility natively. If Pulse is already on the roadmap, the better long-term bet may be "small Nova view onto Pulse" rather than owning this fork.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib