defer() function in Laravel

The new defer() function in Laravel can be really useful when you need to perform an action that the user does not care about or don’t want to wait for it. This can be useful when you are logging user interactions in an analytical database that takes a couple milliseconds or even seconds but you don’t want your user to wait for that to finish (something they have no interest in) before they can navigate.

While you could use Laravel’s Queue (Jobs) to achieve this but it’s just a lot of cumbersome to create a job that just calls a single function or method. The defer() make it much more easier and faster to do it. That’s what Laravel is about, easy & quick! A lot of reading, now let’s jump to some examples.

For the first example, let’s say you have a route in which you want to log what the user did and then predict something about the user and your algorithm to do that is very complex and can take a second. So you might have something like this:

Route::get('/my-page', function () {
    Analytics::interacted(); // This takes 1 second to complete -> ❌  Not Good
    
    return view('my-page');
});

Now with this setup, whenever a user visits the /my-page it takes 1 second just to calculate the analytics while what’s user interested in takes just a couple milliseconds (rendering part). So the user needs to wait an extra second here, we don’t want that. And to avoid that problem, what you could do is wrap the analytics part into a defer function. Here’s how to do it:

Route::get('/my-page', function () {
    defer(fn () => Analytics::interacted()); // User don't wait for this at all --- ✅ Great!

    return view('my-page');
});

Now that we have wrapped that part into the defer() function, Laravel will skip this part of the codes when handling the user request hence the user won’t need to wait for the analytical computing to finish before the request is completed. But if Laravel skips this part when handling the user request then how does it run and does not just skip this part? To answer that question, let’s see how the defer() function in Laravel works actually.

How defer() function in Laravel works

In order to not hold a user request to be sent to the user browser for something the user has no interest in, Laravel will perform whatever the defer() function holds AFTER the response has been sent to the user browser. This is because the modern PHP let’s us to perform actions after the response has been sent to the user. In order for defer() function work make sure your server or hosting provider uses PHP FPM (FastCGI Process Manager) to handle requests. Of course, you don’t need to worry about PHP FPM if you are using Forge, Laravel Cloud, or Vapor.

We have a small problem to handle

Now since defer() function runs the wrapped code after the response has been sent to the user, there are a few things to consider. What if the request fails, does my defer() function still runs? Well, the user to it depends on either you want your code to run even if the request fails or only the request was successful. By default, Laravel will not execute the defer() function if the request is failed. But we can change that. You just need to change the always() method to the defer() function. Here’s how:

Route::get('/my-page', function () {
    defer(fn () => Analytics::interacted())->always(); // Will always run defer once executed

    return view('my-page');
});

This will make sure that your wrapped code in the defer() function runs after it’s executed even if the request fails. One thing to keep in mind is that the defer() function must be executed in order to work, if the request fails or some exceptions get thrown BEFORE the defer() function then it won’t work since the request never reached the defer() function, it will only always run if something went wrong AFTER the defer() function is executed.

The defer() function is not limited to only routes but you can also use it in an artisan command, queues and wherever you want it in Laravel.

Here’s a video of Taylor Otwell himself explaining the defer() function:

3 thoughts on “defer() function in Laravel”

  1. I noticed the Laravel defer helper was released today, and I’m curious if you’ve tried it before its official release? I’ve personally tested it and noticed that while it does make Blade rendering seem faster in the browser, the network tab still shows additional processing before everything fully completes. In other words, the view appears to load quickly, but there’s still some background loading happening. I also tried using defer in my Laravel project with Inertia, but my frontend still waits for the HTTP request to complete even though the response seems ready. Do you know why this happens, and is there a way to handle this in Inertia’s frontend?

    Reply
    • Yes it just got released today, I will remove the note. When you use the defer() function, the request is technically is not completed but only the response has been sent to the user client, so the request is still in progress even though you see the response. Regarding the Inertia, I personally don’t use it so I can’t really help you on that. But I recommend to watch the Laracon US 2024 where Taylor introduced new features for Inertia so they might have covered this part.

      Reply

Leave a Comment