We earn commissions when you shop through the links below.
If you’ve spent any time building Laravel applications with background jobs, you’ve probably run into this decision: this Laravel Horizon vs Laravel Queue tutorial is going to clear up the confusion once and for all. Both are part of the Laravel ecosystem, both deal with queued jobs — but they serve very different purposes, and mixing them up can lead to misconfigured apps and production headaches.
Let me break down what each one actually is, how to set them up, and when you should reach for one over the other.
What is Laravel Queue?
Laravel Queue is the core queue system built into the Laravel framework itself. It lets you defer time-consuming tasks — sending emails, processing uploads, hitting external APIs — to background workers so your HTTP responses stay fast.
Out of the box, Laravel supports multiple queue drivers:
- sync — runs jobs immediately in the same process (no real queuing, useful for testing)
- database — stores jobs in a MySQL/PostgreSQL table
- Redis — uses Redis as the queue backend (fast and recommended for production)
- SQS — Amazon’s managed queue service
- Beanstalkd — older option, rarely used in modern stacks
To dispatch a job, you create a job class and push it onto the queue:
// Create the job
php artisan make:job SendWelcomeEmail
// Dispatch it
SendWelcomeEmail::dispatch($user);
// Run a worker
php artisan queue:work redis --queue=defaultThat’s the core of it. The queue:work command starts a long-running process that picks up and executes jobs. You can run multiple workers, set retry limits, configure timeouts, and prioritize queues — all through command-line flags or your config/queue.php file.
The limitation with plain Laravel Queue is visibility. You have no dashboard, no metrics, no easy way to see which jobs are failing, how many are pending, or how your workers are performing. You’re flying blind in production.
What is Laravel Horizon?
Laravel Horizon is a first-party package built on top of Laravel Queue that adds a beautiful dashboard, supervisor-style process management, and real-time metrics — but it only works with Redis.
Horizon is not a replacement for the queue system. It’s a management layer on top of it. When you install Horizon, you’re still using Laravel’s queue infrastructure under the hood — you’re just getting a much better way to configure and monitor it.
Install it via Composer:
composer require laravel/horizon
php artisan horizon:install
php artisan migrateThen instead of running queue:work manually, you run:
php artisan horizonHorizon reads from your config/horizon.php file and automatically manages worker processes based on your configuration. Here’s a sample config showing multiple environments with different worker pools:
'environments' => [
'production' => [
'supervisor-1' => [
'maxProcesses' => 10,
'balanceMaxShift' => 1,
'balanceCooldown' => 3,
'queue' => ['critical', 'default', 'low'],
'balance' => 'auto',
'minProcesses' => 1,
'tries' => 3,
'timeout' => 60,
],
],
'local' => [
'supervisor-1' => [
'maxProcesses' => 3,
'queue' => ['default'],
],
],
],The dashboard lives at /horizon in your app and shows pending jobs, throughput, failed jobs, wait times per queue, and per-job runtime metrics. You can also tag jobs for filtering and searching through the UI.
Key Differences at a Glance
| Feature | Laravel Queue | Laravel Horizon |
|---|---|---|
| Driver support | Redis, database, SQS, sync, Beanstalkd | Redis only |
| Dashboard | None | Yes, built-in |
| Auto-scaling workers | Manual (you manage processes) | Yes (balance strategies) |
| Metrics & monitoring | No | Yes |
| Failed job management | Via CLI / database | Dashboard UI |
| Setup complexity | Low | Moderate |
| Extra cost | None | Requires Redis |
When to Use Plain Laravel Queue
Reach for plain queue workers (without Horizon) when:
- You’re using the database driver — Horizon doesn’t support it
- You’re on a small project or prototype where Redis adds unnecessary complexity
- You’re processing jobs via Amazon SQS — Horizon won’t help here
- You just need a quick worker with minimal ops overhead
For small apps deployed on something like Railway, a single queue:work process running alongside your web server is perfectly sufficient. You can always migrate to Horizon later when you outgrow it.
When to Use Laravel Horizon
Switch to Horizon when:
- You’re already using Redis (or willing to add it)
- You’re running jobs in production at scale and need visibility
- You want automatic worker scaling based on queue depth
- You need to debug failed jobs without digging through log files or database tables
- Multiple developers need access to job monitoring without SSH access
The auto-balancing feature alone is worth it. With the auto balance strategy, Horizon will shift worker processes toward whichever queue has the most backlog, then redistribute when things calm down. You don’t manage this manually.
Running Horizon in Production
Don’t just run php artisan horizon in a screen session. Use a proper process supervisor. Here’s a Supervisor config:
[program:horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/horizon.log
stopwaitsecs=3600The stopwaitsecs=3600 is important — it gives Horizon time to finish processing the current job before the process is killed during a deploy.
If you’re hosting on DigitalOcean with a VPS or Droplet, Supervisor is available via apt and this setup works out of the box. Managed Redis is also available as an add-on, which means you’re not running Redis yourself.
After each deployment, reload Horizon gracefully:
php artisan horizon:terminateSupervisor will automatically restart it after termination, picking up your new code.
Securing the Dashboard
By default, Horizon’s dashboard is only accessible in local environments. For production, add authorization in app/Providers/HorizonServiceProvider.php:
protected function gate(): void
{
Gate::define('viewHorizon', function (User $user) {
return in_array($user->email, [
'admin@yourapp.com',
]);
});
}Or scope it to a user role if you’re using something like Spatie Permissions.
Final Verdict
This Laravel Horizon vs Laravel Queue tutorial comes down to one key question: are you using Redis and do you need visibility into your jobs in production?
If the answer is yes — and for any serious production app, it usually is — install Horizon. The dashboard pays for itself the first time you need to debug why 200 emails didn’t go out at 2am.
If you’re still early-stage, using the database driver, or want to keep infrastructure minimal, plain queue:work with a supervisor is a solid, zero-dependency choice that you can evolve later.
Either way, understanding both sides of this Laravel Horizon vs Laravel Queue tutorial means you’ll make the right call for your specific situation — instead of just picking whatever you saw first in the docs.