Cache::flexible(): Best way to cache in Laravel

Caching large set of data that has been computed before is always a good idea to make your website faster and one of the most common things we as developer do is using the remember() method of Cache class, but there are some problems with this approach that Laravel fixed. In this post, we will see a better way to cache data in Laravel with the help of the new Cache::flexible() method.

Identifying the problem

We always had that dashboard that shows a lot of stats requiring bunch of SQL queries and computing to calculate them and it takes around 5-10 seconds to only compute these and then show them to the users. That’s bad! And we have Cache::remember() to solve that problem which has it’s own problems that we will discuss later. For now, let’s see how we would solve this using remember() method, here’s an example:

// ❌ Not Ideal
Route::get('/stats', function () {
    $stats = Cache::remember('stats', 5, function () {
        return collect([
            'users' => Stats::users(),
            'teams' => Stats::teams(),
            'events' => Stats::events(),
        ]);
    });

    return view('dashboard', ['stats' => $stats]);
});

The codes above will cache our computed data (that takes 5 seconds to compute) for 5 seconds and whenever another request is made to /stats within 5 seconds, Laravel won’t calculate it again but instead return the cached values (stats). But if a user makes a request after 5 seconds then the cache is not valid anymore and it needs to recalculate. This might works for some of the developers where the cached values don’t expire for a long time but it’s not ideal for short-term cache because there has to be one unlucky user to needs to wait for 5 seconds.

Now that’s our problem, we always have a user that needs to wait for 5 seconds while Laravel cache the stats and then show it to the user.

Solving the problem with Cache::flexible()

In the recent Laracon US conference, Taylor Otwell explained how this problem can be solved using the new Cache::flexible() method. Now we let’s see how the Cache::flexible() actually works and solves our problem.

How Cache::flexible() works

In simple words, the Cache::flexible() will compute and cache the values in the background within a provided time frame. Cache::flexible() uses the new defer() function to cache the values after the response has been sent to the user browser.

It’s better to understand this with an example, let’s use the same case scenario we used in the previous example:

// ✅ Perfect for most use cases
Route::get('/stats', function () {
    $stats = Cache::flexible('stats', [5, 10], function () {
        return collect([
            'users' => Stats::users(),
            'teams' => Stats::teams(),
            'events' => Stats::events(),
        ]);
    });

    return view('dashboard', ['stats' => $stats]);
});

We only changed a few things with these codes, we changed the Cache::remember() method to Cache::flexible() method and instead of passing a single integer for the time, now we are passing an array of 2 integers for time. Let me explain what these codes will do now.

When a user hit the /stats, we unfortunately have to wait for the values to be cached (but that’s the only time we wait), the second time the user hits the /stats route, we show the cached value like we did with Cache::remember() but the real magic happens after first provided integer for the time (in our case 5), if a user hits the /stats route after 5 seconds but before 10 seconds, for example after 6 seconds then Laravel will send the cached value again but this time Laravel will start refreshing the cache in the background without the user even waiting for it. And when the user hit this route on the 7th second then the user gets fresh values without him waiting for the values to be cached again.

That’s the main problem that Cache::flexible() solves, the user only wait once for the values to be cached and then when the user keeps hitting the route within the time frame provided, Laravel will starting caching the values in the background without keeping the user wait for the values to be cached again.

Although for some of the use cases, Cache::remember() might be a good option if the data does need to refresh frequently or their page does not get that much visits but Cache::flexible() solves a huge problem if your page needs fresh data very frequently and get visited a lot.

I recommend to watch this video of Taylor Otwell introducing this feature himself:

Leave a Comment