Laravel — New defer()
Function
The game-changer you didn’t know you needed!
Laravel 11 introduced an exited function called defer()
that will probably change the way you perform time-consuming actions . Let’s understand what this function does and which problems it solves.
What is `defer()`?
The new helper function allows you to run simple tasks asynchronously in the background, allowing the app’s main flow to continue independently. It is designed to delay the execution of specific actions until after the HTTP response is returned to the user.
Like a queued job? Simpler! You don’t need to configure or maintain any jobs, queue workers, or specific classes.
How `defer()` works?
When you use the helper, it takes the block of code registered in the callback and wait for the main request to be complete. Once it is successfully done (with HTTP status codes below 400), it executes the delayed task.
Let’s see an example where the app sends an email when a new user is created:
// app/Services/UserService.php
namespace App\Services;
use App\Models\User;
use App\Services\Notifications;
use function Illuminate\Support\defer;
class UserService
{
public function createUser(array $userData)
{
$user = User::create($userData);
defer(fn () => Notifications::sendWelcomeEmail($user));
return $user;
}
}
One more, when you hit /report
with valid data to generate a report that can get done in the backgroud:
Route::post('/report', function (ReportRequest $request) {
$reportData = $request->validated();
defer(fn () => ReportService::generateReport($reportData));
return response()->json([
'status' => 'Report is being generated'
], 200);
});
You can also cancel a deferred function. For this, you need to define the function name providing a second argument to the defer and then use the forget()
method to cancel the function by it’s name:
// app/Services/UserService.php
namespace App\Services;
use App\Models\User;
use App\Services\Notifications;
use function Illuminate\Support\defer;
class UserService
{
public function createUser(array $userData)
{
$user = User::create($userData);
defer(fn () => Notifications::sendWelcomeEmail($user), 'welcomeMail');
if (!$this->postCreateVerification($user)) {
$deferredEmail->cancel('welcomeMail');
}
return $user;
}
private function postCreateVerification(User $user): bool
{
// some vefification
return true;
}
}
When to use defer()
defer()
is useful for simple and short background tasks when you want to free up the main execution flow without needing queues, workers or cache. For these specific scenarios it works well because it keeps things simple and fast. However, there are some limitations to consider before choosing this approach:
- There is no persistence: If the process is lost, the task is lost. You might miss something important if something goes wrong. With Redis, for example, you have a guarantee that the task will be completed.
- Scalability: In high-volume email scenarios,
defer()
can overload server resources, as it relies on the request’s runtime without advanced queue management. - Monitoring and Control: With Redis and queues, you have full control over task execution, including retries, monitoring, and greater flexibility for adjustments.
defer()
doesn’t allow for task management in case of failure.
Thank you for reading, guys!