Laravel Queue Monitor: Horizon style job monitoring on the database driver
Monitoring Laravel Jobs with your Database
At a glance
- What is it?
- Laravel Queue Monitor gives a Laravel application a jobs table, a small web interface and artisan commands for stale and purge handling, without requiring Redis or the Horizon package. Jobs opt in through a trait, report progress with a percentage, and failed jobs keep their exception.
- Who is it for?
- Laravel Queue Monitor is the right choice for a Laravel team on the database queue driver that needs to see what a job is doing, how far along it is and why it failed, without adding Redis and Horizon to the stack, because it is one trait, one migration and a table you already have a database for.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 16 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Monitoring for the database queue
Laravel Queue Monitor is a package that offers monitoring like Laravel Horizon, for the database queue. That one clause defines the whole market for it.
Horizon is the official dashboard for Laravel's Redis queue, and it is a substantial dependency: a Redis instance, a dedicated service, and a queue connection that is not the default. Teams that run Laravel on the database driver, or that have decided against Redis, have no equivalent.
The feature list is what you would want from such a dashboard. Jobs can be monitored for any queue. Failing jobs are handled with the exception stored, so the reason a job died is in the database rather than in a log file. Job progress can be reported, which gives an estimated time remaining. Additional data can be attached to a monitored job, and jobs can be retried from the user interface rather than from the command line.
The implementation is deliberately plain. There is a trait you add to a job class, a migration that creates a monitoring table, and a routes file that serves a web interface. The package is MIT licensed, published on Packagist as romanzipp/laravel-queue-monitor, and the repository carries a build badge, a code style configuration and PHPStan configuration.
Installing and publishing the pieces
The install is one Composer line.
composer require romanzipp/laravel-queue-monitorThe configuration and the migration have to be published into your application, and the README gives the command that does both in one go.
php artisan vendor:publish --provider="romanzipp\QueueMonitor\Providers\QueueMonitorProvider" --tag=config --tag=migrationsThen the monitoring table is created with the standard migrate command.
php artisan migrateThe table name is configurable, either in the configuration file or in the published migration itself, which matters if your application already has naming conventions for its tables.
There is a separate companion package for Laravel Nova, romanzipp/Laravel-Queue-Monitor-Nova, which adds Nova resources and metrics rather than the package's own interface. If your admin is Nova, that is the route rather than the built-in UI.
The README also links upgrade guides for each major version, with the 5.0 guide flagged for people updating to that release, and separate guides for moving from 3.0 to 4.0, 2.0 to 3.0 and 1.0 to 2.0. Those guides are the thing to read before an upgrade, because the package has crossed four major versions since it started.
Opting a job in with a trait
Monitoring is opt in per job class, and the opt in is a trait.
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use romanzipp\QueueMonitor\Traits\IsMonitored; // <---
class ExampleJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
use IsMonitored; // <---
}The job keeps all its usual Laravel traits and gains one more, and the README marks the two lines that matter with comments.
There is a requirement that is easy to miss and the README bolds it. The job class has to implement the ShouldQueue interface, otherwise Laravel will not dispatch any events containing status information, and the monitor has nothing to listen to. A job that runs synchronously, or one dispatched directly rather than through the queue, produces no monitoring data at all.
The consequence for design is that the trait only gives you visibility into jobs that are genuinely queued, so a monitoring dashboard that looks empty may mean the jobs are not queued rather than that they are fast.
The web interface and the artisan housekeeping commands
The package ships its own web interface, reachable at the /jobs route, and it is disabled by default. You turn it on by setting the enabled value in the configuration file to true.
The frontend assets are built with Tailwind CSS and have to be published as well.
php artisan vendor:publish --provider="romanzipp\QueueMonitor\Providers\QueueMonitorProvider" --tag=assetsThe repository shows how that frontend is built: a package.json with a watch script running the Tailwind CLI against an input stylesheet into a dist file, and a production script that minifies the same output. The compiled assets are committed in the dist directory, and the views and routes directories hold the templates and the route definitions.
Two artisan commands do the housekeeping, and both are meant to be scheduled.
The first marks old monitoring entries as stale. The command takes a before option with a date, a beforeDays option with a number of days, a beforeInterval option taking an interval date string, and a dry option for a dry run. The README says to run it regularly in the console kernel.
The second deletes old monitoring models, and it adds a queue option to restrict the purge to certain queues given as comma separated values, and an only-succeeded option to limit it to successful entries. Either the before or the beforeDate arguments are required for it to run.
That is the design detail worth noting: the table grows forever unless something removes it, and the package hands you a scheduled command rather than a retention policy, which means the interval is your decision.
Reporting progress and estimating the remaining time
The interesting capability is progress reporting, because a job that takes ten minutes is indistinguishable from a job that has hung without it.
A monitored job sets a progress value between 0 and 100, and the monitor turns that into an estimated time remaining.
public function handle()
{
$this->queueProgress(0);
// Do something...
$this->queueProgress(50);
// Do something...
$this->queueProgress(100);
}For the very common case of iterating over a large collection, there is a chunk helper. The job counts the records, chooses a chunk size, and inside the chunk callback it reports the chunk progress, so the percentage reflects how far through the collection the job is rather than how far through one chunk.
Two refinements are worth knowing about.
The first is the cooldown. If a job updates its progress in a tight loop, every update is a database write. Overriding the progressCooldown method with a number of seconds sets the minimum interval between writes, and the README notes the exception that the cooldown is always ignored for the values 0, 25, 50, 75 and 100, so the milestones are always recorded immediately.
The second is custom data. The monitoring model accepts additional key value pairs set from the job, which is where you would put the identifier of whatever the job is processing, so the dashboard can show what it is working on rather than only how far it has got.
Versions, upgrades and what to check before adopting
The release tags are 5.0.0 from 2023-09-11, 4.0.0 from 2023-05-12 and 3.0.0 from 2023-03-28, and the last push to the repository was on 2026-10-11.
So the published version line is several years old while the branch is still receiving commits, which is a normal shape for a Laravel package that has to keep up with framework versions without churning its own major number.
The compatibility question for a new adopter is therefore about Laravel and PHP versions rather than about the package. The topic list still carries a php7 tag, which tells you where the package came from, and the composer file and the CI workflow are where the current supported range is recorded.
Before adopting, four checks are worth doing. Confirm your queue connection is the database driver, because the package's premise is that you are not on Horizon. Confirm your jobs implement ShouldQueue, since without that contract there are no events and nothing to display. Decide how often the stale and purge commands run, since the table is otherwise unbounded. And read the upgrade guide for your version, because the package has had four major versions and the configuration keys are what tend to move.
The MIT licence means there are no obligations beyond attribution if you want to fork it and keep the monitor in step with your own application.
Editorial conclusion
Laravel Queue Monitor is the right choice for a Laravel team on the database queue driver that needs to see what a job is doing, how far along it is and why it failed, without adding Redis and Horizon to the stack, because it is one trait, one migration and a table you already have a database for. It is the wrong choice for an application that already runs Horizon, since the two overlap, and the wrong choice for a job that must report progress in fine granularity, because every update is a database write. Verify first that your queue driver is the database driver rather than Redis, that your jobs implement the ShouldQueue contract so Laravel emits the events the monitor listens to, and that your scheduler runs the stale and purge commands on a sensible interval.
Frequently asked questions
What does Laravel Queue Monitor do?
It offers monitoring like Laravel Horizon for the database queue, letting you monitor jobs for any queue, store the exception on failed jobs, report job progress with an estimated time remaining, attach extra data to a job and retry jobs from the web interface.
How do I monitor a Laravel job?
Add the IsMonitored trait to the job class and make sure the job implements the ShouldQueue contract, since Laravel only dispatches status events for queued jobs. Then publish the configuration, migration and assets and run the migration.
How do I report progress from a job?
Call the progress method with a value between 0 and 100 inside the job handler, and for jobs iterating over large collections use the chunk progress helper inside the chunk callback. A progress cooldown method can be overridden to limit how often updates are written to the database.
Does the monitoring table get cleaned up automatically?
No. You schedule the stale command to mark old entries and the purge command to delete them, both of which accept a date, a number of days or an interval string, and the purge command can be limited to certain queues or to succeeded entries only.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/romanzipp-laravel-queue-monitor)Was this useful?