If your Laravel app is sending emails, generating PDFs, calling third-party APIs, or processing uploads synchronously — users are waiting for all of that before they get a response. Queues fix this. They let you push slow work into the background and return a response immediately, making your app feel instant even when it's doing heavy lifting behind the scenes.
This guide covers everything from basic setup to production-grade queue management — including the exact queue:work flags you need to prevent memory leaks in production.
1. How Laravel Queues Work
The concept is simple: instead of doing work now, you push it onto a queue and a background worker picks it up and processes it asynchronously. The HTTP request finishes immediately, and the user never waits.
2. Setting Up Redis as Your Queue Driver
Laravel supports several queue drivers — database, Redis, Amazon SQS, and others. For production, Redis is the right choice. It's in-memory, extremely fast, and integrates perfectly with Laravel Horizon.
phpredis extension instead of predis for better performance. Install it with sudo apt install php-redis on Linux.
3. Creating Your First Job
Use Artisan to generate a job class. Let's create one that sends a welcome email after a user registers — a classic use case that should never run synchronously.
ShouldQueue on jobs you want to run asynchronously. Without it, the job runs synchronously even if you dispatch it — a common gotcha that's easy to miss.
4. Dispatching Jobs
5. queue:work Flags — --max-jobs, --max-time & More
This is the most important section for production. Getting these flags right prevents memory leaks and keeps your queues healthy long-term.
| Flag | What it does | Recommended value |
|---|---|---|
--max-jobs |
Exit after processing N jobs | 500 Use in production |
--max-time |
Exit after N seconds | 3600 (1 hour) Use in production |
--memory |
Exit if memory exceeds N MB | 256 |
--sleep |
Seconds to sleep when no jobs available | 3 |
--tries |
Max attempts before marking job as failed | 3 |
--timeout |
Seconds before a job is killed | 60 |
--queue |
Which queues to process (priority order) | critical,default |
--max-jobs restarts after a job count — good for high-traffic queues. --max-time restarts after a time window — catches memory leaks even on low-traffic queues that process few jobs. Together they cover both scenarios. Supervisor or Horizon automatically restarts the worker after each exit.
6. Keeping Workers Running with Supervisor
In production, you need a process manager to keep your queue workers alive when they exit after --max-jobs or --max-time. Supervisor is the standard solution on Linux servers.
The numprocs=4 setting runs 4 parallel worker processes. With autorestart=true, Supervisor automatically restarts each worker after it exits from --max-jobs or --max-time.
7. Installing and Using Laravel Horizon
Horizon is the official Redis queue dashboard from the Laravel team. It replaces manual Supervisor config with code-driven worker configuration and gives you a real-time dashboard for monitoring everything.
QUEUE_CONNECTION=redis is set in your .env before installing.
app/Providers/HorizonServiceProvider.php to restrict access to admin users only.
8. Handling Failed Jobs
9. Queue Best Practices for Production
Always use --max-jobs and --max-time together
Never run queue:work in production without these flags. PHP processes accumulate memory over time — restarting workers periodically is the simplest way to keep memory usage stable.
Use dedicated queues by priority
Always restart workers after deployment
10. Conclusion
The most important takeaway for production: always use --max-jobs and --max-time together with Supervisor or Horizon to keep workers healthy and memory usage stable. It's a small config change that prevents the most common production queue issues.
Start with the database driver locally, move to Redis in production, and add Horizon once you need visibility into what's happening. For related reading, check out the Laravel Performance Optimization guide — the natural next step after queues are working.