Back to Blog
    Laravel 13 queuesLaravel queuesLaravel jobsLaravel queue workerLaravel failed jobsLaravel Redis queueLaravel background jobsLaravel queue best practices

    Laravel 13 Queues & Jobs: A Practical Guide to Background Processing | Abhilash Raj

    Learn Laravel 13 queues and jobs with practical examples covering queue drivers, workers, retries, failed jobs, delayed jobs, batching, and production best practices.

    2026-09-08 · Abhilash Raj · 14 min read

    Laravel 13 Queues & Jobs: A Practical Guide to Background Processing | Abhilash Raj

    Laravel 13 Queues & Jobs: A Practical Guide to Background Processing

    Not every task in a Laravel application needs to happen while the user is waiting for an HTTP response.

    Sending emails, processing images, generating reports, importing large files, sending notifications, and calling external APIs can all take time. Performing these operations directly during a web request can make an application feel slow.

    Laravel queues provide a clean solution.

    Instead of making the user wait for a long-running task, your application can place the task on a queue and process it in the background.

    In this practical Laravel 13 guide, we'll explore jobs, queues, queue connections, workers, retries, failed jobs, delayed jobs, batching, monitoring, and production best practices.

    What Are Laravel Queues?

    A queue allows Laravel to postpone work that doesn't need to happen immediately.

    Without a queue, a request might look like this:

    User
      ↓
    HTTP Request
      ↓
    Laravel
      ↓
    Process image
      ↓
    Send email
      ↓
    Generate report
      ↓
    Return response
      ↓
    User waits
    

    With a queue:

    User
      ↓
    HTTP Request
      ↓
    Laravel
      ↓
    Create Job
      ↓
    Queue
      ↓
    Return response
      ↓
    User continues
           ↓
    Queue Worker
           ↓
    Process Job
    

    The second approach can dramatically improve perceived application responsiveness.


    What Is a Laravel Job?

    A job represents a specific piece of work that Laravel can execute.

    For example:

    php artisan make:job SendWelcomeEmail
    

    Laravel creates a job class that can contain the logic for sending the email.

    A simplified job might look like:

    namespace App\Jobs;
    
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Queue\Queueable;
    
    class SendWelcomeEmail implements ShouldQueue
    {
        use Queueable;
    
        public function handle(): void
        {
            // Send the email
        }
    }
    

    The important part is:

    implements ShouldQueue
    

    This tells Laravel that the job should be processed asynchronously by a queue worker.


    Why Use Queues?

    Queues are particularly useful for tasks that are:

    • Slow
    • Resource intensive
    • Not required immediately
    • Dependent on external services
    • Repetitive
    • Suitable for background processing

    Common examples include:

    Email

    Send welcome email
    Send invoice
    Send password notification
    Send marketing email
    

    Image processing

    Resize image
    Generate thumbnails
    Compress images
    Create WebP versions
    

    Reports

    Generate PDF
    Export CSV
    Generate monthly reports
    

    External APIs

    Sync CRM data
    Send webhook
    Call payment service
    Import third-party data
    

    Creating a Queue Job

    Create a job using Artisan:

    php artisan make:job ProcessOrder
    

    A job can receive the data it needs through its constructor.

    For example:

    class ProcessOrder implements ShouldQueue
    {
        use Queueable;
    
        public function __construct(
            public int $orderId
        ) {}
    
        public function handle(): void
        {
            // Process the order
        }
    }
    

    You can then dispatch the job:

    ProcessOrder::dispatch($order->id);
    

    The job is now placed onto the configured queue.


    Dispatching Jobs

    A common pattern is:

    SendWelcomeEmail::dispatch($user);
    

    Laravel takes care of placing the job onto the configured queue connection.

    You can also dispatch a job after a specific delay.

    For example:

    SendWelcomeEmail::dispatch($user)
        ->delay(now()->addMinutes(10));
    

    This is useful when a task should not execute immediately.


    Synchronous vs Asynchronous Processing

    There is an important difference between executing a job immediately and placing it on a queue.

    A synchronous job effectively runs during the current request.

    A queued job is placed on a queue and processed by a worker.

    For production applications, asynchronous processing is generally preferable for genuinely long-running tasks because it prevents the web request from being blocked.


    Queue Connections

    Laravel supports multiple queue backends through queue connections.

    The queue configuration is defined in:

    config/queue.php
    

    The appropriate connection is selected through your application's environment configuration.

    For example:

    QUEUE_CONNECTION=database
    

    or another supported queue backend appropriate for your infrastructure.

    The correct choice depends on your application's workload and hosting environment.


    Database Queues

    The database queue is a convenient option for applications that already use a relational database.

    You can create the required queue table using the appropriate Laravel Artisan command for your application version, then run:

    php artisan migrate
    

    Once configured, jobs can be stored in the database until a worker processes them.

    Database queues are easy to understand and can work well for smaller applications.

    However, high-volume applications may benefit from a dedicated queue system.


    Redis Queues

    Redis is a popular choice for higher-performance queue processing.

    A typical configuration can use:

    QUEUE_CONNECTION=redis
    

    The application then pushes jobs into Redis and queue workers retrieve them.

    Redis can be a strong option when your application needs:

    • High queue throughput
    • Fast job dispatching
    • Multiple workers
    • Large numbers of background tasks

    For a growing SaaS application, Redis-based queues are often worth considering.


    Running a Queue Worker

    Creating jobs isn't enough.

    Something needs to process them.

    That's the purpose of the queue worker.

    A basic worker can be started with:

    php artisan queue:work
    

    The worker continuously checks the queue for new jobs.

    When a job becomes available, it processes the job and moves on to the next one.


    Understanding Queue Workers

    A worker can be thought of as a background process:

    Queue
      │
      ├── Job A
      ├── Job B
      ├── Job C
      └── Job D
            ↓
       Queue Worker
            ↓
       Execute Job
    

    If you need more processing capacity, you can run multiple workers.

    For example:

    Queue
     │
     ├── Worker 1
     ├── Worker 2
     └── Worker 3
    

    The appropriate number of workers depends on your workload and available server resources.


    Queue Worker Options

    Laravel provides options for controlling how workers behave.

    For example:

    php artisan queue:work --tries=3
    

    This allows a job to be attempted multiple times before it is considered failed.

    You can also specify a queue:

    php artisan queue:work --queue=emails
    

    This is useful when you separate workloads into different queues.

    For example:

    emails
    reports
    notifications
    imports
    

    Named Queues

    You can send jobs to a specific queue:

    SendWelcomeEmail::dispatch($user)
        ->onQueue('emails');
    

    Then run a worker specifically for that queue:

    php artisan queue:work --queue=emails
    

    This allows you to prioritize different types of background work.

    For example, you might want email jobs to have different processing capacity from large report-generation jobs.


    Queue Priorities

    You can process queues in a specific order.

    For example:

    php artisan queue:work --queue=high,default
    

    The worker can prioritize the queues according to the configured order.

    This is useful when some jobs are more important than others.

    For example:

    high
      ↓
    emails
      ↓
    default
      ↓
    reports
    

    A production application can use this strategy to make sure important work doesn't get stuck behind expensive background tasks.


    Job Retries

    External services fail.

    Networks fail.

    APIs become temporarily unavailable.

    Databases can experience temporary problems.

    For this reason, queue jobs should be designed with retries in mind.

    For example:

    public int $tries = 3;
    

    This tells Laravel that the job can be attempted multiple times.

    You can also configure retry behavior according to the requirements of the job.


    Exponential Backoff

    Retrying a failed API request immediately several times isn't always a good idea.

    A better approach can be to wait progressively longer between attempts.

    For example:

    public function backoff(): array
    {
        return [10, 30, 60];
    }
    

    This provides increasing delays between attempts.

    Backoff is particularly useful when interacting with external APIs that may temporarily reject requests.


    Handling Failed Jobs

    Sometimes a job will continue failing even after retries.

    Laravel provides failed-job handling so you can identify these failures.

    A failed job can be stored for later inspection depending on your queue configuration.

    You can inspect failed jobs with:

    php artisan queue:failed
    

    You can retry a failed job using the appropriate queue retry command.

    For example:

    php artisan queue:retry all
    

    This gives you a way to recover from temporary failures without manually repeating the original operation.


    The failed() Method

    A job can define a failed() method for cleanup or notification logic.

    For example:

    public function failed(?Throwable $exception): void
    {
        // Notify the team or perform cleanup
    }
    

    This can be useful for:

    • Logging failures
    • Sending administrator notifications
    • Updating database status
    • Cleaning temporary files
    • Recording integration failures

    Make Jobs Idempotent

    One of the most important queue concepts is idempotency.

    A job may run more than once.

    For example:

    Attempt 1
       ↓
    Payment API request
       ↓
    Timeout
       ↓
    Retry
       ↓
    Payment API request again
    

    If your job isn't designed carefully, this could potentially create duplicate operations.

    For critical operations, design jobs so that running them more than once doesn't produce an incorrect result.

    For example, use unique transaction identifiers or database checks where appropriate.


    Avoid Passing Huge Objects to Jobs

    Be careful about putting large amounts of data into queued jobs.

    Instead of passing a huge collection:

    ProcessOrders::dispatch($orders);
    

    consider passing identifiers:

    ProcessOrders::dispatch($orderIds);
    

    or, where appropriate, a model identifier.

    The worker can retrieve the required data when processing the job.

    This keeps queue payloads smaller and easier to manage.


    Queueing Eloquent Models

    Laravel can serialize supported Eloquent model instances for queued jobs.

    For example:

    SendInvoice::dispatch($invoice);
    

    However, remember that relationships and large object graphs can increase the amount of data involved.

    For predictable queue payloads, keep the job's input as small as practical.


    Job Middleware

    Laravel jobs can also use middleware.

    Job middleware is useful when you need to apply behavior around job execution.

    Potential use cases include:

    • Rate limiting
    • Preventing overlapping jobs
    • Controlling concurrency
    • Releasing jobs back onto a queue

    For example, if a third-party API limits requests per minute, queue middleware can help control the request rate.


    Preventing Overlapping Jobs

    Imagine your application generates a report every hour.

    If the report takes longer than an hour, another report could start while the first one is still running.

    That may waste resources.

    Job-level controls can be used to prevent overlapping work when the operation should be unique or serialized.

    This is especially important for:

    • Reports
    • Imports
    • Synchronization tasks
    • Data processing
    • Scheduled jobs

    Queue Batches

    Laravel also supports processing multiple jobs as a batch.

    This is useful for large operations.

    For example:

    Import 100,000 customers
            ↓
    Create many jobs
            ↓
    Batch
     ├── Job 1
     ├── Job 2
     ├── Job 3
     ├── Job 4
     └── ...
    

    Batches can provide progress tracking and lifecycle callbacks.

    This makes them useful for large imports, exports, and multi-step processing workflows.


    Queue Events

    Laravel provides queue events that can be useful for monitoring application behavior.

    You can track events such as:

    • Job processing
    • Job completion
    • Job failure
    • Job retries

    These events can be used for logging, metrics, and operational monitoring.


    Queues and Notifications

    Queues work particularly well with notifications.

    Instead of making the user wait while multiple notifications are sent, you can queue the notification work.

    This is useful for applications that send:

    • Email notifications
    • Database notifications
    • External service notifications

    For applications with significant notification volume, background processing can make a noticeable difference to request performance.


    Queues and Mail

    Sending an email can involve network communication with an external mail service.

    Instead of:

    HTTP request
     ↓
    Generate email
     ↓
    Connect to mail service
     ↓
    Send email
     ↓
    Wait
     ↓
    Return response
    

    a queued workflow can be:

    HTTP request
     ↓
    Dispatch email job
     ↓
    Return response
           ↓
    Queue worker
           ↓
    Send email
    

    This is a common and practical use case for Laravel queues.


    Queues and File Processing

    Image processing is another excellent queue candidate.

    Imagine a user uploads a large image.

    Instead of making the upload request perform every operation:

    Upload
     ↓
    Resize
     ↓
    Compress
     ↓
    Create thumbnails
     ↓
    Optimize formats
     ↓
    Return response
    

    you can return quickly after the upload and process the remaining operations in the background.

    This can make applications feel significantly faster.


    Queues and Large Imports

    Suppose an administrator uploads a CSV containing 100,000 records.

    Processing everything in a single HTTP request is risky.

    Instead:

    CSV Upload
        ↓
    Read file
        ↓
    Split into chunks
        ↓
    Create jobs
        ↓
    Queue
        ↓
    Workers process chunks
    

    This architecture is more scalable and allows the application to handle large imports without tying up a web request.


    Queue Workers in Production

    Running:

    php artisan queue:work
    

    manually in a terminal isn't a reliable production strategy.

    If the terminal closes, the worker can stop.

    Production workers should be managed by a process supervisor or an appropriate process-management system.

    The supervisor should be able to:

    • Start workers
    • Restart crashed workers
    • Keep workers running
    • Manage multiple workers
    • Handle deployments safely

    On VPS infrastructure, this is an important part of production Laravel deployment.


    Restart Workers During Deployment

    Laravel workers are long-running processes.

    When application code changes, workers may still have old code loaded in memory.

    For this reason, your deployment process should include a worker restart strategy.

    A common Laravel command is:

    php artisan queue:restart
    

    This signals workers to gracefully restart after completing their current job.

    Your deployment process should ensure that new workers load the latest application code.


    Queue Worker Memory Management

    Long-running workers can gradually consume memory depending on the jobs they execute and the libraries they use.

    Monitor memory usage and configure worker limits appropriate to your application.

    For example:

    php artisan queue:work --memory=256
    

    The exact value should be based on your server's available resources and the memory requirements of your jobs.

    Don't blindly increase memory limits to hide memory leaks.

    Investigate jobs that continually increase memory usage.


    Queue Timeouts

    Long-running jobs should have appropriate timeout settings.

    A timeout that is too short can terminate legitimate work.

    A timeout that is too long can cause workers to remain occupied for excessive periods.

    Choose timeouts based on the actual work performed by the job.

    For example, a simple email job may need very little time, while a large report-generation job may require significantly more.


    Database Transactions and Queues

    Be careful when combining database transactions with queued jobs.

    For example:

    DB::transaction(function () use ($order) {
    
        $order->update([
            'status' => 'paid',
        ]);
    
        ProcessOrder::dispatch($order);
    
    });
    

    Depending on when the queued job is processed, it may run before the surrounding database transaction has committed.

    For jobs that depend on committed database state, use the appropriate transaction-aware dispatching approach.

    This prevents workers from trying to read data that isn't committed yet.


    Don't Put Everything Into a Queue

    Queues are powerful, but not every operation needs background processing.

    For example:

    Simple database lookup → synchronous
    Simple validation → synchronous
    Small calculation → synchronous
    Large PDF generation → queue
    Large image processing → queue
    External API synchronization → queue
    Bulk import → queue
    

    The goal isn't to maximize the number of queued jobs.

    The goal is to move expensive or delay-tolerant work away from the user's request.


    Laravel Queues and Application Performance

    Queues are closely connected to overall Laravel performance.

    Your application might have:

    Slow database queries
            ↓
    Eloquent optimization
            ↓
    Caching
            ↓
    Queues
            ↓
    Web server optimization
    

    Article 5 in this series covers database optimization:

    Laravel 13 Database Optimization: Eloquent, Indexing & Query Performance

    For broader performance techniques, see:

    Laravel 13 Performance Optimization: Practical Tips to Make Your Application Faster

    And if you're deploying your Laravel application to a VPS:

    How to Deploy a Laravel Application on a VPS

    Practical Laravel Queue Architecture

    A production application might look like this:

                        Laravel Application
                               │
                 ┌─────────────┴─────────────┐
                 ↓                           ↓
            HTTP Requests                 Queue
                 │                           │
                 ↓                           ↓
            Controllers                 Redis / Database
                 │                           │
                 ↓                           ↓
            Database                   Queue Workers
                                             │
                        ┌────────────────────┼─────────────────┐
                        ↓                    ↓                 ↓
                      Emails              Reports          API Sync
    

    This architecture separates user-facing requests from background processing.

    As the application grows, workers can be scaled independently from the web application.


    Laravel Queue Production Checklist

    Before deploying queues to production, verify:

    Queue configuration

    ✓ Correct queue connection
    ✓ Correct environment variables
    ✓ Production queue backend configured
    

    Workers

    ✓ Workers running
    ✓ Workers managed by a process supervisor
    ✓ Worker memory limits configured
    ✓ Worker timeout configured
    

    Jobs

    ✓ Jobs have appropriate retry limits
    ✓ Failed jobs are monitored
    ✓ Long-running jobs have suitable timeouts
    ✓ Jobs are idempotent where necessary
    

    Deployment

    ✓ New code deployed
    ✓ Queue workers restarted
    ✓ Configuration/cache updated
    ✓ Failed jobs monitored after deployment
    

    Useful Artisan Commands

    Here are several commands worth remembering.

    Start a worker

    php artisan queue:work
    

    Process a specific queue

    php artisan queue:work --queue=emails
    

    Limit attempts

    php artisan queue:work --tries=3
    

    Restart workers

    php artisan queue:restart
    

    List failed jobs

    php artisan queue:failed
    

    Retry failed jobs

    php artisan queue:retry all
    

    Clear failed jobs

    php artisan queue:flush
    

    Always verify the available command options against the Laravel version and queue configuration used by your application.


    Conclusion

    Laravel queues provide one of the most practical ways to improve the responsiveness and scalability of a Laravel application.

    Instead of making users wait for expensive operations, you can move appropriate work into background jobs and let queue workers process it independently.

    The most important concepts to understand are:

    • Jobs
    • Queue connections
    • Queue workers
    • Delayed jobs
    • Retries
    • Backoff
    • Failed jobs
    • Job idempotency
    • Queue priorities
    • Queue batches
    • Job middleware
    • Worker memory limits
    • Worker timeouts
    • Production worker management

    Start simple.

    For a small application, a database-backed queue may be enough. As the workload grows, a dedicated queue backend such as Redis can provide a stronger foundation for high-throughput background processing.

    The key principle is straightforward:

    Don't make the user wait for work that doesn't need to happen during the request.

    Move expensive, slow, or delay-tolerant operations into queues and let your Laravel application respond quickly.

    When combined with database optimization, caching, efficient application code, and proper production server configuration, queues can become an important part of a scalable Laravel architecture.

    Advertisement

    Share this post

    Comments

    Loading comments...

    Related articles

    Follow new notes

    Use the RSS feed in your reader. For questions, start a WhatsApp conversation.

    RSS feed