Skip to main content

What are queues?

Web applications often need to perform tasks that take several seconds to complete: sending emails, resizing images, calling external APIs, or generating reports. Running these tasks synchronously during an HTTP request means users wait until the work finishes. Laravel’s queue system lets you push these tasks to a background queue and return a response immediately. A worker process picks up the jobs and executes them separately.
Laravel supports multiple queue backends—database, Redis, Amazon SQS, and more. During development, the sync driver executes jobs immediately without a real queue, so no worker is required.

Queue setup and configuration

config/queue.php

All queue configuration lives in config/queue.php. Switch the backend by setting the QUEUE_CONNECTION environment variable:

.env settings

Setting up the database driver

The database driver stores jobs in a database table. In Laravel 11+, new projects already include the required migration. If yours doesn’t, run:

Setting up the Redis driver

Install the Predis package and configure a Redis connection in config/database.php:
Then set QUEUE_CONNECTION=redis in .env.

SQS overflow storage

Amazon SQS limits the maximum queued message payload size. If your jobs may exceed that limit, you can store oversized payloads in a cache store and send only a pointer through SQS:
  • When enabled is true, payloads that are at least 1 MB are stored in the configured cache store.
  • When always is true, every SQS payload is stored in the cache store regardless of size.
  • delete_after_processing removes stored payloads after successful processing (default: true).
  • If flush_on_clear is true, queue:clear flushes the overflow store. Use a dedicated cache store so normal cache data is not removed.

Creating and dispatching jobs

Generating a job class

Create a job with the make:job Artisan command:
This generates app/Jobs/SendWelcomeEmail.php.

Job class structure

Implementing ShouldQueue tells Laravel to push the job onto the queue instead of running it synchronously. The Queueable trait provides the methods needed to configure and dispatch the job.
When you pass an Eloquent model to a job constructor, Laravel serializes only the model’s ID. The worker re-fetches fresh data from the database at execution time, keeping the queue payload small.

Dispatching a job

Push a job onto the queue by calling dispatch:

Dispatching to a specific queue

Send a job to a named queue to separate different priorities:

Queue routing

Instead of calling onQueue() and onConnection() on every job dispatch, use the Queue facade’s route method in a service provider’s boot() to define default routing rules for specific job classes:
You can route by interface, trait, or parent class — any job that implements, uses, or extends it will inherit the rule. To route multiple job classes at once, pass an array:
Queue routing can still be overridden per-dispatch with onQueue() or onConnection().

Synchronous dispatch (for testing and development)

Skip the queue and run a job immediately with dispatchSync:

Bulk dispatching

When you need to dispatch many independent jobs at once without batch tracking or callbacks, use the bulk method on the Bus facade. Laravel groups the jobs by their configured queue connection and queue name, then pushes each group to the appropriate queue in bulk:
Bus::bulk() sends jobs to the queue in bulk groups. Unlike Bus::batch(), it doesn’t provide progress tracking or completion callbacks. Use it when you want to efficiently dispatch a large number of simple, independent jobs in one call.

Delayed dispatching

Delay job execution with the delay method. Pass a DateTime or a duration:
dispatchAfterResponse runs the job right after Laravel sends the HTTP response to the browser, so the user isn’t kept waiting:

Job chaining

Chain jobs so they run sequentially. If one job in the chain fails, subsequent jobs are not run:
You can also attach a callback that runs when the entire chain completes:

Job batches

Batching lets you dispatch a collection of jobs and track their collective progress. Start by creating a migration for the job_batches table:
Implement the Batchable trait in your job class:
Dispatch a batch using Bus::batch:
Inspect a batch by its ID:

Running the queue worker

Start a worker process with:
Target a specific connection or queue:
queue:work runs continuously. After deploying new code, run php artisan queue:restart to reload workers with the latest changes. In production, use a process manager like Supervisor to keep workers running.

Worker options

Setting retries and timeouts on the job class

You can configure retry and timeout behavior directly on the job using PHP attributes:

Releasing jobs with middleware

Use the Release middleware when a job should return to the queue instead of running under a particular condition.
Release::unless() releases the job when the condition is false:
Use a closure for more complex conditions:
Releasing a job still increments its attempt count. Configure #[Tries] or the $tries property appropriately.

Failed jobs

Preparing the failed_jobs table

When a job exceeds its maximum attempt count, Laravel records it in the failed_jobs table. Create the table if it doesn’t exist:

Handling failure in the job

Define a failed method to run cleanup logic when a job fails:

Stopping retries by exception

Some exceptions indicate that a job should fail immediately rather than be retried. Configure these exception types using dontRetry in bootstrap/app.php:
For finer control, pass a closure to dontRetryWhen. When the closure returns true, the job is marked as failed immediately without further retries:
Use this for exceptions where retrying would never succeed — for example, validation errors, expired subscriptions, or permanent third-party rejections.

Managing failed jobs

Queue drivers compared

For production Redis queues, consider Laravel Horizon. It provides a real-time dashboard to monitor job throughput, wait times, and failures.

Example: order confirmation email

1

Create the job

2

Implement the job logic

3

Dispatch from the controller

4

Start the worker

Common use cases

  • Sending email, SMS, or push notifications
  • Resizing or converting images and video
  • Calling slow external APIs or webhooks
  • Generating reports or exporting CSV files
  • Indexing records in a search engine
Set QUEUE_CONNECTION=sync in your .env during development. Jobs run immediately without a worker, making it easy to test the full flow without extra processes.
Last modified on July 13, 2026