Top 12 Tips for Laravel Performance Optimization

Today, Laravel has become a very popular framework for developing business and E-Commerce applications. Most of the organizations prefer Laravel to build their business applications. There are numerous reasons for that. But today we will only focus on performance optimization.

8 mins read
Jul 15, 2021

Today, Laravel has become a very popular framework for developing business and E-Commerce applications. Most of the organizations prefer Laravel to build their business applications. There are numerous reasons for that. But today we will only focus on performance optimization.

Why should we need performance optimization?

As we are talking about the two words Performance and Optimization, these are the two key factors of application success. Performance is the crucial part of the application which every developer should focus on before delivering the application. Whereas, Optimization of the code directly affects the performance of the application.

I have some of the important tips which will help you to optimize the application code and increase performance:-

  1. Eager Loading
  2. Eloquent Paginate, Chunk, Cursor
  3. Route Cache
  4. Config Cache
  5. Reduce Package Usage
  6. Queues
  7. Remove Unused Services/Files/Code
  8. Assets Bundling
  9. Assets Minifying
  10. Composer Optimize Autoload
  11. Fast Cache or Session Drivers
  12. Database Indexing

1. Eager Loading

When we get data from a database using Laravel, then it loads data on demand. Which is a good practice. But when we talk about loading relational data, this practice slows down the performance and this process is called Lazy Loading.

In some cases, this lazy loading behavior increases the amount of queries executed and at the same time decreases the performance of the application.

Below is a simple example to understand the behavior of lazy loading and how we can resolve this.

We have books, and every book has an author.

With lazy loading, we will end up executing N+1 queries to find out the result.

$books = App\Models\Book::all();

foreach ($books as $book) {
      echo $book->author->name;
}

In the above code, every time the `foreach` loop executes, then the query to fetch author name gets executed. Below are the queries running:-

  • Select * from books;
  • Select * from authors where authors.id=? Limit 1;
  • Select * from authors where authors.id=? Limit 1;
  • Select * from authors where authors.id=? Limit 1;
  • …..

To resolve this problem, Laravel provides us eager loading with the use of `with()` function, which loads all the mentioned relational data and appends with the correct place.
By using this the number of queries execution will decrease and along with that execution time will increase. The below code sample shows how we can easily load the complete list of data before processing.

$books = App\Models\Book::with(‘author’)->get();
foreach ($books as $book) {
      echo $book->author->name;
}

After implementation of eager loading, queries running behind:-

  • Select * from books;
  • Select * from authors where authors.id in (?, ?, ?, ?);

So it is good practice to use eager loading wherever need to fetch relational data.

2. Eloquent Paginate, Chunking, Cursor

Laravel Eloquent provides us with some powerful features like Paginate, Chunking, Cursor, etc. Most of the time, we use Laravel’s get() or all() functions, which works perfectly for small data sets. But when we talk about a large dataset then it hardly hits performance issues. So to overcome this issue, use paginate() or chunk() function, which is mostly used to efficiently process the big numbers of models.

For the use of Paginate below is the example:-

use App\Models\User;
User::paginate(10)
Passing Eloquent models to a processing closure, the chunk method will retrieve a subset of the models. As only the current chunk of Eloquent models is rectified at a time, the chunk method will give significantly reduced memory usage while working with a big number of models.

use App\Models\User;

User::chunk(100, function ($users) {
      foreach ($users as $user) {
          //
      }
});

The cursor method executes a single database query only but the individual Eloquent models don’t get hydrated until they are actually iterated over. Hence, only one Eloquent model will be kept in the memory at any given time while iterating over the cursor. Cursor method reduces application’s memory consumption when iterating a large number of records using Eloquent Model.

use App\Models\User;

foreach (User::cursor() as $user) {
//
}

3. Route Cache

Laravel allows us to cache application routes. This is a very essential feature when an application has lots of routes. Laravel firstly reads all the routes from the route files and then converts them to an array. Whenever we refresh the screen or request to the laravel application, everytime laravel reads routes from the files and then converts to an array and uses those.

But Laravel provides us with a single command to read all the routes of the application, convert to array and cache them.

php artisan route:cache

Remember to run every time this command, whenever route files will be changed. Otherwise laravel loads old cached routes and new changes in route file will not reflect. For clear the route cache use below given command:-

php artisan route:clear

Note: Don’t use route cache command on the development server. This command is built especially for production environments.

4. Config Cache

As we know Laravel allows us to cache all the routes, in the same way Laravel allows us to cache all the application configuration.

php artisan config:cache

This will combine all the configuration options into a single file which will be loaded quicker by the application.

5. Reduce Package Usage

Laravel is very famous in the open source community and almost daily we can see new packages are releasing or new releases in existing packages. By which we can directly use these packages in our application and use their features.

To include these packages we need to add packages in composer.json file and after that Laravel will install these packages along with their dependencies.

But before adding new packages into the application we have to look carefully on the dependencies of the packages. All the packages are not built to achieve a single purpose. Some of the packages are built to do a number of functionalities. If we will add such packages which have lots of dependencies, in that case the size of the application also increases.

6. Queues

Queues are the process, how we are handling requests, when we have to perform heavy tasks. It directly affects the user experience.

As an example, when a user registers to the website, then we have to perform many actions in the backend like store user information, send activation mail, and send welcome mail, etc. If we simply send a mail (without queues) then it will take around 4-5 seconds. And the user has to wait until the request. So, with queues, we just need to push actions inside the Queues after performing required validations and showing a user success message. After that we just need to handle basic things when queues will execute.

7. Remove Unused Services

Laravel provides a convenient way to inject services to the application using the service container. We can use any service by adding into the providers array in the config/app.php file.

But most of the time, we are using services which are not needed everywhere in the application. So if we include such services on load that will impact on application performance.
To solve this problem, we can inject service where it is needed. There are two ways to inject service inside class such as controller:-

  • Inject service inside class constructor function: Sometimes we need to inject service before class load. So that after load the service we can use that anywhere in the class.
  • Inject service inside needed function of class: Sometimes we need any service only in a single method of class. So in that case, service should inject the inside function itself.

By method injection, we can reduce the burden on the application while loading and increase the performance. So we have to make sure that unused/less used services should be removed from the config/app.php file.

8. Assets Bundling

Assets Bundling
Laravel has a package called Laravel Mix, which comes by default in all Laravel Applications. Laravel Mix offers an effective API that enables you to define Webpack build ups for your PHP applications using several common CSS and JavaScript preprocessors. To compile application assets including JavaScript, CSS and others, Laravel Mix is very useful for the compilation. With the help of Laravel Mix, we can combine many css files into a single file.

mix.js(‘resources/js/app.js’, ‘public/js’)
      .sass(‘resources/sass/app.scss’, ‘public/css’);

9. Assets Minifying

As we understand that we can combine multiple css/js files into one single file which will make it large in size. But that would not help in improvement in performance. So to resolve this issue, Laravel Mix allows us to minify such files. Below is the command to minify the files.

npm run prod

Generally, we run this command when our assets are ready for production. After executing the command, files get minified and the assets become smaller, which will be retrieved faster and also speed up the performance of our application. Besides this, we can also use Content Delivery Network(CDN) which refers to a geographically distributed group of servers and works together to provide speedy delivery of the Internet content.

A CDN allows for the quick transfer of assets needed for loading Internet content including HTML pages, JavaScript files, stylesheets, images, and videos. CDN services have been a popular choice of people since the beginning. Talking about current status, the majority of web traffic is served through CDNs today including traffic from brands like Amazon, Facebook, and Netflix.

10. Composer Optimize Autoloader

Laravel is designed in such a way that it autoload all the classes when requests initiate. To load all the classes Laravel needs to scan the whole filesystem to read classes.

This is very helpful during the development process, we don’t have to change autoload configuration every time when we add a new file. But as a file is searched in the file system every time, that will lower the performance of the application.

In order to address this slowness, Composer provides us with such class-mapping, and scans all the classes of the filesystem and creates mapping of the classes. Now, Laravel just needs to read only a single file, where all the class mappings are stored. That increases the performance of the application.

To create class mapping we need to run below command

composer dump-autoload

11. Fast Cache or Session Drivers

Fast Cache or Session Drivers

To improve performance of Laravel applications, we can store sessions and cache in RAM. Memcached is the best and fastest cache and session driver for this. Laravel is flexible to switch one cache/session drive to another.

For the session driver we can change driver key in config/session.php and for cache we can change driver key in config/cache.php file.

12. Database Indexing

When we are talking about increasing the performance of the application, we are following many practices in Laravel like caching, data loading, asset minification, etc. But there is one more thing, which can help us to improve performance, i.e. database indexing. This is basically a database level technique.

Basically, database indexing is data structuring which is based on one or more columns of the database table. The main idea behind indexing is to speedup data retrieval. It helps in locating the data easily without needing to go through each and every row, every time the database is accessed.

Using columns, indexing helps in minimizing the disk accesses for each query which is processed. Making the database indexing a powerful technique for database optimization, It also improves the overall database performance.

In Laravel we can create indexing by the use of migrations. Below is the example:-

Schema::create(‘users’, function (Blueprint $table) {
      …
      $table->string(’email’)->index();
      …
});

Conclusion

At the end, there are many more ways to optimize performance of the application(which we have not covered in this article). But I’m sure, after implementation of the above-mentioned tips, the developer who works in the Laravel framework to create and maintain business applications could make sure that the software they are building runs fast and is optimized for performance.

Laravel App Maintenance