# Skyline for Laravel vs Laravel Queue Monitor

> Laravel Queue Monitor logs the jobs you opt in to a database table, on any driver. Skyline replaces Horizon on Redis, alerts when the queue stops working and lets you act on it.

Source: https://boring-observability.dev/skyline/vs/laravel-queue-monitor
Section: Comparisons — Skyline for Laravel
Updated: 2026-11-11

---

**Bottom line:** These two overlap less than their names suggest. Laravel Queue Monitor is a free log: add its trait to a job class and every run lands in a database table with its status, exception, progress and any data you attach, on any queue driver. Skyline replaces Horizon on Redis and works on the live queue, alerting when Horizon stops or a queue stalls and letting you pause one queue or release a stuck unique lock. Pick Laravel Queue Monitor for long-term history of a few job classes, or if you are not on Redis. Pick Skyline when the problem is finding out late and then being unable to act.

[Laravel Queue Monitor](https://github.com/romanzipp/Laravel-Queue-Monitor), by Roman Zipp, has been around since 2018 and is one of the most installed queue packages for Laravel. It and Skyline for Laravel are often weighed against each other because both promise a better view of your jobs than the framework gives you. They get there from opposite directions. Laravel Queue Monitor writes the jobs you opt in to a table in your database, on any queue driver. Skyline replaces `laravel/horizon` on Redis and works on the live queue.

This page describes Laravel Queue Monitor as of version 5.5.0, released in October 2026.

## What each one records

Laravel Queue Monitor records a job only if its class uses the `IsMonitored` trait. Each run of that job becomes a row in a `queue_monitor` table: its status, queue, attempt number, start and finish times, the full exception trace if it failed, a progress percentage the job can report, and any data you attach. The rows stay until you delete them, so a month later you can still ask when an import last finished and how long it took.

Skyline records every job on your Redis queues without touching a job class, because it is the Horizon install those queues already run under. That history lives in Redis for Horizon's trim windows, which are measured in hours, so it is gone long before a month has passed. What Skyline adds is the live side: alerts when the queue stops working, and controls to act on it while it is still broken.

## At a glance

| Capability | Laravel Queue Monitor | Skyline |
| --- | --- | --- |
| Relationship to `laravel/horizon` | Runs alongside it, or without it | Replaces it |
| Queue drivers | Any that fires Laravel's queue events | Redis |
| Which jobs are recorded | Classes that use the `IsMonitored` trait | Every job on your Redis queues |
| Where history lives | A table in your database, kept until you purge it | Redis, for Horizon's trim windows |
| Progress reporting and custom data per job | Yes | No |
| Exception trace for each attempt | Yes, one row per attempt | [Yes, earlier attempts kept on the job](https://boring-observability.dev/skyline/docs/dashboard-operations#previous-attempts) |
| Metrics | Jobs run, total and average runtime over 14 days | [Throughput, runtime and wait per queue and class, with 24-hour trends](https://boring-observability.dev/skyline/docs/metrics-and-trends) |
| Alerts | None | [Seventeen checks over mail, Slack, SMS or a webhook](https://boring-observability.dev/skyline/docs/alerts) |
| Queue length, wait time and worker status | No | Yes, on Horizon's dashboard |
| Retry a failed job | Yes, through `queue:retry` | Yes |
| Pause a single queue | No | [Yes](https://boring-observability.dev/skyline/docs/pausing-queues) |
| Run a delayed or retrying job immediately | No | [Perform Now](https://boring-observability.dev/skyline/docs/dashboard-operations#perform-now) |
| Scheduled task runs, including missed ones | No | [Schedule screen](https://boring-observability.dev/skyline/docs/scheduled-tasks) |
| Held `ShouldBeUnique` locks and skipped dispatches | No | [Locks & Limits screen](https://boring-observability.dev/skyline/docs/locks-and-limits) |
| Memory and CPU per job class | No | [Opt-in insights](https://boring-observability.dev/skyline/docs/insights) |
| Access control on the dashboard | Middleware you add; the route ships with none | [Horizon's `viewHorizon` gate](https://boring-observability.dev/skyline/docs/security-and-access#the-gate) |
| Database migrations | One table | None |
| Requirements | PHP 8.2+, Laravel 12 or 13 | PHP 8.0+, Laravel 9.21 to 13, Redis |
| Price | Free, MIT | $139 once, a year of upgrades |

## A log of job activity

Its maintainer describes the dashboard as "more a backlog of job activity rather than a dashboard", and that is the right way to read it. Each attempt is its own row, so a job that failed twice and then succeeded shows up three times. A job whose worker was killed mid-run stays marked as running until the `queue-monitor:stale` command marks it stale. Nothing is pruned on its own: you schedule `queue-monitor:purge` with the retention you want, or tell a job class to delete its row when it succeeds.

The page at `/jobs` is off by default, and its route ships without the `web` middleware group or any authentication. Add both to `ui.route.middleware` before you enable it in production.

## Where Laravel Queue Monitor is the better answer

- **You are not on Redis.** It records jobs from the database driver or SQS, or from anything else that fires Laravel's queue events. Skyline, like Horizon, is Redis only.
- **You need history that outlives Redis.** Rows sit in your own database for as long as you keep them, and Eloquent scopes such as `failed()` and `today()` make them easy to query.
- **You want a progress bar on long jobs.** A job can report 0 to 100 percent as it runs and attach its own data, which you can then filter the list by. Skyline has no equivalent.
- **Budget is the constraint.** It is free, MIT-licensed, one table and one page.

## Where Skyline is the better answer

- **You need to hear about it.** Laravel Queue Monitor has no notifications. Skyline checks the live fleet every minute for Horizon being down, a stalled queue, failure spikes and crash-looping workers, and sends a recovery message when each one clears.
- **You need to act on a live queue.** Pausing one queue during an incident, or running a retrying job the moment the fix is deployed, works on Redis state that a table of past runs cannot reach.
- **You do not want to edit every job class.** A job without the trait is invisible to Laravel Queue Monitor. Skyline sees every job on the queues it runs.
- **The job never ran at all.** A dispatch skipped by a held `ShouldBeUnique` lock leaves no row in any table, and neither does a scheduled task that was due and never started. Skyline's Locks & Limits and Schedule screens exist for exactly those.
- **You want queue length and worker status.** Laravel Queue Monitor shows the jobs it recorded, not how many are waiting or who is working on them. That is Horizon's dashboard, which Skyline keeps.

## Can you run both?

Yes, and that is a reasonable setup for a team that wants long-term history on a few important job classes. Laravel Queue Monitor listens for Horizon's `JobPushed` event when Horizon is installed, and Skyline keeps the `Laravel\Horizon` namespace and fires the same events, so it should behave the same way it does beside upstream Horizon. The two use separate storage and separate pages, `/jobs` and `/horizon`.

> **Expected, not yet certified**
>
> We have not run the pairing ourselves. Try it on staging first, and if you do run them together, we would like to hear how it went.

## Choosing between them

If the question you keep asking is "what happened to that job last week?", or you are not on Redis, Laravel Queue Monitor answers it for free. If it is "why did nobody notice the queue had stopped?", that is Skyline.


## Common questions

### Does Laravel Queue Monitor send alerts?

No. As of version 5.5.0 it has no notifications of any kind: it records job runs in a table and shows them on a page. Skyline runs seventeen checks against the live queue every minute, including Horizon not running, a stalled queue, failure spikes and crash-looping workers, and sends each alert over mail, Slack, SMS or a webhook with a recovery message when it clears.

### Does Laravel Queue Monitor record every job?

Only the job classes that use its IsMonitored trait, and only queued ones. A job without the trait is never recorded. Skyline, as your Horizon install, sees every job on your Redis queues without changes to any job class.

### Does Laravel Queue Monitor work with Horizon?

Yes, beside it. When Horizon is installed it listens for Horizon's JobPushed event, and it replaces nothing in Horizon: it keeps its own table and its own page at /jobs. Skyline keeps the Laravel\Horizon namespace and fires the same events, so the pairing is expected to work the same way, though we have not certified it.

### How long does Laravel Queue Monitor keep job history?

Until you delete it. Nothing is pruned on its own: you schedule queue-monitor:purge with the retention you want, and a job class can ask for its row to be deleted when it succeeds. Skyline keeps Horizon's Redis history for Horizon's trim windows, which are measured in hours, so for history that outlives Redis, a database log like this one is the right tool.

### Is the Laravel Queue Monitor dashboard protected?

Not by default. The /jobs page is off until you enable it, and its route ships without the web middleware group or any authentication, so add both to ui.route.middleware before you turn it on in production. Skyline's dashboard is Horizon's, behind the viewHorizon gate.

### What does Laravel Queue Monitor require?

Version 5.5.0 needs PHP 8.2 or newer and Laravel 12 or 13, plus a database for its table. It is free and MIT-licensed. Skyline needs PHP 8.0 or newer, Laravel 9.21 to 13 and Redis, and costs $139 once.
