Caching in Laravel with Redis: a complete guide

  • A photo of Kenneth Ekandem By Kenneth Ekandem
  • on Aug 29, 2024
 

Laravel is a web application framework built with PHP. It’s a framework that uses providers and dependency injections for code organization. It follows a model-view-controller design pattern. Laravel reuses the existing components of different frameworks, which helps in creating a web application. Thus, the application is designed to be more structured and pragmatic.

Redis is a disk-persistent advanced key-value store with support for multiple data structures or data types, which means that while it supports mapped key-value-based strings to store and retrieve data (analogous to the data model supported in traditional kinds of databases), it also supports other complex data types, such as lists and sets. Redis is open source, but offers Redis enterprise with some additional features. It's also scalable - running multiple Redis nodes lets you handle even more traffic.

A Laravel Redis integration uses caches for temporary data storage to speed up the process of pulling data out of a database, which will, in turn, reduce the amount of time spent pulling up data.

What is a cache?

A cache is a component that stores data so that future requests for the data can be fulfilled quickly. The data stored in a cache might be the result of an earlier computation or duplicates of data stored elsewhere. Therefore, whenever the same result is needed, one can use the cached value, which has already been computed and stored elsewhere, so there is no need to perform repeated computations of the same thing. You can cache data in Laravel without a Redis server, but it's a common choice for production applications.

Diagram of caching for Laravel Redis Diagram of caching data for a web application

Redis servers use server-assisted client-side caching, which allows them to exploit the available memory of the application servers, which are usually distinct computers compared to the database nodes, to store some subset of database information directly on the application side. Usually, when some data are required, the application servers ask the database about such information, but in a Redis server, the record is retrieved from the local cache.

Before using a Redis server on a computer, it must be set up on your Windows or Mac operating system. If you do not have it installed, you can follow the instructions given in the MacOS or Windows version of the tutorial to set it up. If you're using a Redis server in production, you'll also need to consider how it will run on your infrastructure.

Note: In this tutorial, we will be using Postman as our API client. You can go ahead and use Laravel’s resources to build the view for your application, but it will not be covered in this article.

System Requirements

Benefits of Redis

  1. Redis acts as a temporary database for storing data up to 512 MB in size and allows data lookup to be performed more efficiently and quickly, which will prove useful in large-scale applications.
  2. Redis uses the master-slave data replication structure, which means that slave nodes always listen to the master node, and when data are updated in the master node, the data are also updated in the slave node. All of this can be done asynchronously.
  3. Redis uses a built-in hashing mechanism called Redis Hashing, which stores information in the form of a key and a map.

There are many other benefits to using Redis, but let’s stick to the listed ones for now. More information about Redis is available on its official documentation page

Redis Get and Set methods

Get: This gets a key example blogs from the local cache and returns its value. The Get method only stores strings and will return an error—the key stores hashes or others.

Set: This method sets a key example blogs to hold string values. If a key already exists, then it will override the value(s) of that key, regardless of its type, unless instructed otherwise.

Setting up a Laravel Redis cache

To get started with a Laravel Redis cache, we need to create a new instance of Laravel on our local machine. We create a new Laravel project from our command line with the name laravel-redis, go into the newly created directory containing our files, and run the application:

composer create-project laravel/laravel laravel-redis
cd laravel-redis
php artisan serve

Next, we need to install the predis package in our application using composer prior to using Redis on our application. We will use a Redis client to connect our application to the Redis instance. Predis is a Redis client written entirely in PHP and does not require any additional extensions. There are other Redis clients for PHP, like the phpredis extension, but Predis is quite popular. Run the following command on your terminal to install Predis:

composer require predis/predis

Configuring Redis in Laravel

When the installation is complete, we can find our Redis server configuration settings in config/database.php. In the file, you will see a redis array containing the Redis server configuration. By default, the client is set to phpredis, a different Redis client. Since predis is being used in this tutorial, the Redis client will be changed to predis in the configuration file:

'redis' => [

  'client' => env('REDIS_CLIENT', 'predis'),

  'options' => [
      'cluster' => env('REDIS_CLUSTER', 'redis'),
      'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
  ],

  'default' => [
      'url' => env('REDIS_URL'),
      'host' => env('REDIS_HOST', '127.0.0.1'),
      'password' => env('REDIS_PASSWORD', null),
      'port' => env('REDIS_PORT', '6379'),
      'database' => env('REDIS_DB', '0'),
  ],

],

You can modify the default settings in the configuration file to your own custom settings depending on your particular URL and add a password, but for this tutorial, we won’t be doing that.

After that is done, go ahead to register your REDIS_CLIENT in the .env file with this command so that the configuration file can read that value:

REDIS_CLIENT=predis

Seeding data

I’ve gone ahead and created a database connection in my .env file and seeded a couple of blogs in the database.

Note: This is not a compulsory step but rather a maneuver to avoid going the long route to make a create request.

Use the command below to create a seeder. Then, add a couple of blogs, which we run with the artisan command to seed the data:

php artisan make:seeder BlogSeeder

This will create a new BlogSeeder in your database folder. Next, we will add a couple of blogs:

DB::table('blogs')->insert([
          'title' => 'First blog',
          'sub_header' => 'This is the first sub header',
          'content' => 'BLOG_CONTENT'
      ]);
...

Then, we run the artisan command to seed the data to the database under the blogs table:

php artisan db:seed --class=BlogSeeder

Fetching data

To fetch a blog from the database, we create a blog controller and add a function to fetch a blog using id from the database. On the first request, the blog will be fetched from the database and cached using Redis. However, on subsequent requests, the blog will be retrieved directly from Redis and formatted in JSON, skipping the database queries altogether.

First, we will create a new controller using the following command:

php artisan make:controller BlogController

Then, we add our function to get all blogs:

use App\Models\Blog;
use Illuminate\Support\Facades\Redis;

public function index($id) {

  $cachedBlog = Redis::get('blog_' . $id);


  if(isset($cachedBlog)) {
      $blog = json_decode($cachedBlog, FALSE);

      return response()->json([
          'status_code' => 201,
          'message' => 'Fetched from redis',
          'data' => $blog,
      ]);
  } else {
      $blog = Blog::find($id);
      Redis::set('blog_' . $id, $blog);

      return response()->json([
          'status_code' => 201,
          'message' => 'Fetched from database',
          'data' => $blog,
      ]);
  }
}

In the above code, we are first checking Redis for the key with blog_ + id and returning it in JSON format if it exists. If the key has not been set, then we go to the database, get the key, and set it in Redis using blog_ + id.

Next, we create a route in routes/web.php that our API can interact with when used in Postman. This route will point to our BlogController and, specifically, our function that is fetching the blog:

Route::get('/blogs/{id}', 'BlogController@index');

Updating data

In this process, we will get a single blog and update it in the database. When this is done, we will look up the key in the Redis cache, delete it, and then create a new key with the id of the updated blog.

Before we proceed, I commented out \App\Http\Middleware\VerifyCsrfToken::class, in the app/http/kernel.php file to disable CSRF verification. You shouldn’t do this in an application ready for production, as this is necessary for the protection of the application routes. You can read more about CSRF verification and its usefulness in the Laravel documentation

First, we create our update function in the BlogController:

public function update(Request $request, $id) {

  $update = Blog::findOrFail($id)->update($request->all());

  if($update) {

      // Delete blog_$id from Redis
      Redis::del('blog_' . $id);

      $blog = Blog::find($id);
      // Set a new key with the blog id
      Redis::set('blog_' . $id, $blog);

      return response()->json([
          'status_code' => 201,
          'message' => 'User updated',
          'data' => $blog,
      ]);
  }

}

In the above code, we got the id of the blog, updated it in the database, and then deleted the key and value at that key with blog_ + id. After the key is deleted, we then fetch the blog from the database using the id and create a new key in Redis.

After this is done, we can create our route:

Route::post('/blogs/update/{id}', 'BlogController@update');

Delete data from the cache

For the last part, we will delete a blog from the database and then delete the key and its value from the Redis cache. First, add the delete function:

public function delete($id) {

  Blog::findOrFail($id)->delete();
  Redis::del('blog_' . $id);

  return response()->json([
      'status_code' => 201,
      'message' => 'Blog deleted'
  ]);
}

This will get the id and delete the blog from the database. Then, it will delete the key from Redis. After adding our function, we can then create a route.

Route::delete('/blogs/delete/{id}', 'BlogController@delete';

Tradeoffs of caching for performance

Our walk through a practical Laravel Redis integration should empower you with the knowledge to set up, configure, and utilize Redis caching effectively. We've covered the tricky parts of caching in CRUD apps - fetching, updating, and deleting data - showing how Redis can easily integrate with your Laravel application to optimize endpoints that might take too much time.

The ability to store frequently accessed data in memory translates to reduced database load, lower latency, and a smoother user experience. This is particularly crucial for high-traffic applications where every millisecond counts. Optimizing Laravel applications often starts with caching.

While caching is important for better performance, it also introduces new complexity around data consistency and cache invalidation. We've shown straightforward examples of updating data in a cache, but choosing to cache data locks you into this additional layer of complexity. If you make changes to the underlying data, it's important to always remember to update the cached version of that data as well.

As you implement these techniques in your projects, always consider the specific needs of your application and the potential trade-offs involved. I hope this tutorial is helpful to both you and your users!

Get the Honeybadger newsletter

Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo
    Kenneth Ekandem

    I am a PHP and Javascript developer with 4 years of experience building applications with a variety of tools, languages, and frameworks.

    An advertisement for Honeybadger that reads 'Turn your logs into events.'

    "Splunk-like querying without having to sell my kidneys? nice"

    That’s a direct quote from someone who just saw Honeybadger Insights. It’s a bit like Papertrail or DataDog—but with just the good parts and a reasonable price tag.

    Best of all, Insights logging is available on our free tier as part of a comprehensive monitoring suite including error tracking, uptime monitoring, status pages, and more.

    Start logging for FREE
    Simple 5-minute setup — No credit card required