Hello! In our previous module, we concluded our deep dive into Laravel's authorization system, covering how to define and apply access rules using Gates and Policies. You're now equipped to build applications that are not only functional but also secure.
Today, we shift our focus from security to performance and user experience as we begin a new module on background processing. This lesson introduces one of Laravel's most powerful features: Queues.
You'll learn how to offload time-consuming tasks to a background process, ensuring your application remains fast and responsive for your users. Specifically, we will cover how to create and dispatch jobs to be processed asynchronously.
Why Do We Need Queues?
Imagine a user signs up for your application, and as part of the process, you need to:
- Create their user record.
- Generate a detailed, multi-page PDF welcome packet.
- Send a welcome email with the PDF attached.
If you perform all these tasks during the user's web request, they might be staring at a loading spinner for 5, 10, or even 30 seconds. This is a poor user experience.
30 Days to Learn Laravel, Ep 25 - Queues Are Easier Than You Think
The Laracasts video series you've seen before opens this topic by perfectly framing this exact problem. Watch the first minute to understand the issue with synchronous operations.
Watch from the beginning until 0:56 to see a clear explanation of why making the user wait for tasks like sending an email is not ideal.
The solution is to perform only the essential task synchronously (creating the user record) and defer the slow tasks (generating the PDF, sending the email) to a background process. This is precisely what queues are for.
The Big Picture: Jobs, Queues, and Workers
The concept of a queue is something you're already familiar with from everyday life.
30 Days to Learn Laravel, Ep 25 - Queues Are Easier Than You Think
This video uses a brilliant real-world analogy of a copy shop (Kinko's) to explain the core concepts. It's one of the clearest explanations you'll find.
Watch the segment from 04:11 to 05:59. Pay close attention to the three key terms: Job, Queue, and Worker.
To recap the analogy:
- Job: The task to be done (e.g., "make 300 copies" or "send a welcome email").
- Queue: The place where jobs wait to be processed (e.g., the tray where the copy shop employee puts new orders).
- Worker: The entity that performs the jobs from the queue (e.g., "Stan", the employee in the back who only makes copies).
In Laravel, your web application adds a job to a queue. A separate worker process, running on your server, picks up that job and executes it. This allows your web application to give an immediate response to the user.

1. Configuring Your First Queue
Laravel supports various queue "drivers" (the backend technology that powers the queue), such as Redis, Amazon SQS, or a database table. For getting started, the database driver is the simplest as it doesn't require any extra software.
Let's set it up.
Mastering Laravel Queues: A Complete Guide to Background Job ...
This article provides a concise guide to setting up Laravel queues. We'll follow the first two steps to get our database queue ready.
Read the sections '1. Configuration' and '2. Database Setup'. This will show you how to configure the .env file and generate the necessary database migration.
As described in the article, the two steps are:
-
Set the driver in
.env:QUEUE_CONNECTION=database -
Create and run the jobs table migration:
php artisan queue:table php artisan migrateThis creates a
jobstable in your database. When you dispatch a job, Laravel will insert a new row into this table.
2. Creating a Job Class
Now that we have a place to put our jobs, let's create one. A job is simply a PHP class that contains the logic for the task you want to run in the background.
The Artisan command make:job generates a new job class for you. Let's create a job to handle sending a welcome email.
php artisan make:job SendWelcomeEmail
This command creates a new file at app/Jobs/SendWelcomeEmail.php. Let's examine its structure.
The official Laravel documentation provides the definitive explanation of a job's structure. Understanding this structure is key to building any kind of background task.
Read the sections 'Generating Job Classes' and 'Class Structure'. Focus on the purpose of the ShouldQueue interface, the __construct method, and the handle method.
Here's a breakdown of the key parts of our new app/Jobs/SendWelcomeEmail.php file:
<?php
namespace App\Jobs;
use App\Models\User; // We will use the User model
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log; // For demonstration
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The user instance.
*
* @var \App\Models\User
*/
public $user;
/**
* Create a new job instance.
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*/
public function handle(): void
{
// This is where the time-consuming logic goes.
// For now, we'll just log a message to simulate sending an email.
Log::info("Sending welcome email to: " . $this->user->email);
// In a real application, your mail sending logic would be here:
// Mail::to($this->user->email)->send(new WelcomeEmail($this->user));
}
}
Key Points:
implements ShouldQueue: This interface is the magic. It tells Laravel that this job should be pushed to a queue instead of being run synchronously.__construct(User $user): The constructor receives any data the job needs to perform its task. Here, we need theUserobject to know who to email.handle(): This method contains the actual logic of the job. It's called by the queue worker when it's time to process the job.
3. Dispatching the Job
"Dispatching" a job means adding it to the queue. You typically do this from a controller. Once you've written your job class, you can dispatch it using the static dispatch() method.
Let's turn again to the official documentation to see how to dispatch the job we just created. It's a very straightforward process.
Read the main 'Dispatching Jobs' section. Notice how the arguments passed to dispatch() are passed along to the job's constructor.
Let's modify a hypothetical RegisteredUserController to dispatch our new job instead of sending an email synchronously.
// In a controller, e.g., app/Http/Controllers/Auth/RegisteredUserController.php
use App\Jobs\SendWelcomeEmail;
use App\Models\User;
// ... other use statements
public function store(Request $request): RedirectResponse
{
// ... validation logic ...
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
event(new Registered($user));
// Instead of sending the email here and making the user wait...
// Mail::to($user)->send(...);
// We dispatch a job to the queue. The response is sent immediately!
SendWelcomeEmail::dispatch($user);
Auth::login($user);
return redirect(route('dashboard', absolute: false));
}
That's it! When this code runs, Laravel will create a new SendWelcomeEmail instance, serialize it (including the User model's ID), and store it as a new row in your jobs database table. The user's browser gets an immediate redirect to the dashboard.
But wait... if you check your logs, no message has been written. The job is in the queue, but who is going to run it?
4. Running the Queue Worker
The final piece of the puzzle is the worker. The worker is a command-line process that you run on your server. Its sole purpose is to poll the queue for new jobs and execute them.
To start a worker for your default queue, open your terminal and run:
php artisan queue:work
30 Days to Learn Laravel, Ep 25 - Queues Are Easier Than You Think
Watching a worker in action makes the whole concept click. This video demonstrates starting the worker and seeing it process a previously-queued job.
Watch from 05:59 to 07:01. The video shows the php artisan queue:work command being run and how it immediately processes the job that was dispatched earlier.
Once you run php artisan queue:work, you'll see it waiting for jobs. Now, if you register a new user in your application, you will see the worker's terminal output spring to life, showing that it is processing and completing the SendWelcomeEmail job. If you check your storage/logs/laravel.log file, the message will now be there.
A Crucial Tip: The queue:work process loads the application framework into memory when it starts. This means if you change your code (e.g., update the handle method of your job), you must restart the worker for the changes to take effect. You can stop the worker with Ctrl+C and start it again.
Queues in Laravel: Main Things You Need to Know (Two Examples)
This is a common 'gotcha' for new developers. Both of our video resources make a point of explaining this. Let's see another demonstration to really drive the point home.
Watch from 02:58 to 03:48 to see the worker as a background process. Then, watch the critical segment from 06:20 to 06:46, which explicitly explains why you must restart the worker after code changes.
Conclusion
You've just taken a huge step toward building more professional, scalable, and user-friendly Laravel applications. By offloading slow tasks to a queue, you can provide a snappy user experience while still performing complex operations in the background.
Key Takeaways:
- Why Queues? To improve application performance and user experience by deferring slow tasks.
- The Components:
- Job: A class representing the task to be done.
- Queue: A list of pending jobs (e.g., a database table).
- Worker: A process (
php artisan queue:work) that executes jobs from the queue.
- The Workflow:
- Create a job with
php artisan make:job YourJobName. - Implement the job's logic in its
handle()method. - Dispatch the job from your application (e.g., a controller) using
YourJobName::dispatch(). - Run a worker with
php artisan queue:workto process the jobs. - Remember to restart the worker after you change your job's code.
- Create a job with
Up Next:
In this lesson, we used the simple database driver. In our next lesson, we will explore how to configure and use different queue drivers, including the database driver in more detail and the popular Redis driver, which is often used in production environments for better performance. We will also look at how to run the queue worker more robustly.