Home | About | Blog | Skills | Innovations | Work with Me | Connect with me | Other Links
Published On: Apr 14 2025
Written By: Krishnan Sethuraman
Category: Programming
Albeit what the tech brows on twitter say, Php is a solid programming language that can be used to build amazing software applications.
I maintain and have built multiple Php applications with Php.7.4 and upwards. I have not faced any performance related bottleneck.
My go to framework is Laravel. I moved to the Laravel world in 2016 after four years of working with Codeigniter 3. In addition to working with Codeigniter 3, I have also worked on other frameworks like Slim, CakePHP and Phalcon.
From my experience I must say that Laravel is just amazing. Concepts like the middleware, grouping the routes, having separate routes for web and api etc are just amazing. It makes the source code easy to understand and maintain.
However I am not a big fan of the ORM and I love writing raw sql queries as much as possible. Using raw sql queries makes it easy to analyse and optimise it. Reading a source code also becomes relatively easy with raw sql.
Having said that, this article is not about how awesome Laravel is. It is about how we boost the performance of the Laravel application.
Most of my learnings are from building REST APIs in Laravel so most of the examples that I use will be from that perspective, but the lessons can also be implemented in any type of Laravel application.
With that being said, let's not find out how you can boost the performance of your Laravel application.
Php 8+ has introduced JIT (Just-In-Time) compilation, which dramatically boosts performance.
JIT speeds up your application by compiling frequently used code to machine language and keeps it readily available for future executions. This reduces the need to interpret the code at every execution which directly improves the performance of the underlying code.
If you are beginning to build a new application, going with Php 8.x might be the right decision. It will be a clean start and you can harness the benefits of JIT.
On the other hand things might not be so straightforward for existing applications. In some cases the benefits of upgrading to Php 8.x might not be substantial. It might also require code changes to replace functions that have been deprecated.
For organizations that find upgrading to Php 8.x not viable can skip this and implement the other changes that we have talked about in this article and you should see a remarkable improvement in performance.
In most projects that I have worked, I have seen the database being ignored most of the time. To my surprise even in critical and data intensive projects this is often the case.
Modern frameworks like Laravel and Symfony have made it easy for developers to interact with the data source without a deep understanding of the database. This is convenient in many ways as it increases developer productivity. But it also poses a challenge when the application begins to scale and the size of the database increases.
For a web application to work efficiently it is very important to have a database that is properly designed and well indexed that sits on a server with appropriate resources in terms of CPU and RAM. In addition to that the queries run by my controllers should also be well optimised.
In this subsection we will see how we can optimise our database to super charge our laravel application.
References:
While creating or altering tables make sure your columns have the right data type. I have seen many developers choose VARCHAR for almost all columns. This is the wrong approach. It will not break the application immediately, but will negatively impact the quality of the data and the overall performance.
Always choose the right data type for the columns, Never leave it for later. The so-called "later" will never come. Focus on the data types of the columns like you would focus on the code.
References:
If you are using a RDBMS database like Mysql or Postgres then always use foreign key relationships. This ensures that the data stored in the database is accurate and is of high quality.
Let’s consider a real life example.
Let's say, I am building a project management software and I have two tables called projects and tasks. All the tasks are mapped to project id. So in this case the tasks table will have a column called project_id and that will be related to the primary key column of the projects table. This will ensure that all the tasks inserted in the tasks table are associated with respective projects in the projects table.
This is critical to maintain integrity of the data stored in the database.
The ORM in Laravel makes it easy for the developers to query the database.
While reading Laravel code, in many instances I have seen developers write bad queries with ORM that queries the entire table.
For example, following are two queries which can be used to fetch the posts from the posts table.
Posts::get();
Posts::select(‘id’, ‘title’)->get();
The second query is faster and more efficient than the first query. The reason being in the second query we are only fetching the columns that we need. The first query is slow and inefficient as we are fetching all the columns.
So in your query always select only the columns that are required.
Indexes in your database are like the table of contents in a book. Table of contents in a book help you in navigating to the desired topic quickly and easily. Without the table of content you will have to browse through the entire book to find the topic of your choice.
Similarly in a database table to make the queries more efficient and faster we create indexes. Indexes are like the table of contents.
The indexes are created based on multiple parameters but the base rule is to create indexes in the foreign key columns and in columns which are used in where clause in select queries.
You can also create a composite index. Composite index is an index spanning multiple columns. This will be very useful in optimizing your select queries that have multiple where clauses.
Creating indexes does slow down inserts and updates to the data by a negligible margin. Do not create indexes in all the columns of any given table. Overdoing indexes is also not a good database decision. Create the right indexes and be done with it.
If your application has a considerable amount of users or if the tables that you query have thousands of rows or both then you need to implement a caching layer in your Laravel application.
The two most popular caching applications are Memcached and Redis and Laravel supports both of them.
Memcached is my go to caching application. It is easy to learn and set up. It also supports clustering so it makes it easy to for me to create clusters in the future if required.
Implementing a caching layer drastically reduces the load on the database as the application fetches the data from the caching layer and only hits the database in case the data is not present in the caching layer.
I usually cache all the select query results and delete the cache whenever a related new record is created. The next time when the select query runs it fetches the data from the database and then caches it so that consecutive executions use the caches result.
This blog uses Redis for caching the blog articles. I chose Redis, because Memcached allows only 1 MB of data to be cached. So this can be a valid use case on which caching application should you use for your Laravel application.
In addition to caching data you can also cache the routes in Laravel.
The routes can be cached with the following command.
php artisan route:cache
This command compiles all your routes into a single file for faster performance (especially in production), reducing the time Laravel spends parsing and registering routes.
When your Laravel application receives a HTTP request, a lot of things happen under the hood. One of the things that literraly run for every request is called middleware. Think of middleware as little checkpoint that every request goes through before it reaches the actual method that is associated with a particular api or endpoint. These checkpoints can do things like user authentication and authorization, protect against spam, block a request etc.
Laravel gives you a bunch of these useful middlewares by default, and they're pretty useful. But here's the thing - not all of them are always necessary for every page or action or request. If your app is small or has specific needs, you might by default be running extra middlewares that aren't doing anything valuable but still can slow things down.
So, take a good look at the list of middlewares in your application. If you're not using some of them, especially in your routes or controllers, consider removing them. Less stuff running means your app responds faster.
Same goes for autoloading. Laravel tries to be helpful by loading a bunch of stuff automatically. But again, if you're not using something, there's no need to keep it around. Unused service providers, extra packages, or custom helpers that load on every request can all add unnecessary weight.
Here’s a simple way to think about it:
The fewer things your app has to load and process, the quicker it can respond.
Quick tips:
composer.json
and remove extra packages that aren’t actually used.It might seem like a small change, but cleaning up your middleware and autoloading can help your Laravel app breathe easier and perform better - especially when your app starts growing and receives more traffic.
Queueus are another important aspect in building an application that has the potential to scale to huge amounts of traffic. With queues you can execute code asynchronously.
All heavy lifting activities like like sending emails, integrating with third-party APIs, generating reports can all be done asynchronously with queues and workers.
Reference:
Every time a user hits a route, your app should respond as fast as possible. If you're doing long operations inside the controller or service layer, you're blocking the response cycle. This leads to:
Laravel's queue system allows you to offload slow tasks to background workers, which means your app can respond instantly, while the task finishes behind the scenes.
Let's understand this with better with an example.
Let's say I have a user signup module that sends out an email after successful completion of signup. For sending the email you are using a third party service like Sendgrid or Brevo.
The regular approach is to write a method that compeletes the signup process and integrates to the third party API that sends a welcome email. Now this is a long and process which blocks the server from accepting new requests.
An alternate approach is to use queue and worker. There are plenty of queues available. SQS, Pub/Sub, RabbitMQ, Benastalkd and so on.
I use RabbitMQ extensively for our queue needs as it is opensource and also supports clustering.
So in the new approach you would finish the signup process and then instead of integrating the third party email service APIs you would dispatch the message to the queue and hend the request. You can have queue names for each and every process to make it easier to understand and manageable.
The job associated with the queue will now pick up this message and ansynchronously integrate with the third party api and complete the process of sending the email.
Here’s how it works in a nutshell:
<?php
// Dispatch a job to the queue
SendWelcomeEmail::dispatch($user)->onQueue('send_welcome_email');
This creates a queued job that your worker (like `php artisan queue:work`) processes in the background.
Use queues for any job taking more than 200-300ms. The smaller your controller logic, the faster your app feels.
References:
If you're running a high-traffic Laravel app or API, Laravel Octane can give your performance a serious boost—like 10x faster response times under load.
Laravel Octane is a package that boots your app once and keeps it in memory, serving requests using Swoole or RoadRunner. This eliminates the need to boot Laravel on every single request.
Traditional PHP apps (with Apache/Nginx + FPM) spin up Laravel every time. Octane flips that model and keeps things hot.
Install via Composer:composer require laravel/octane
php artisan octane:install
Then choose your server (Swoole or RoadRunner) and run:php artisan octane:start