Maximizing Laravel Performance: Essential Optimization Strategies for Web Developers

A cozy winter scene with a web developer focused on their laptop screen, which prominently displays "Laravel Optimization".

When it comes to websites, performance of applications/websites have an impact on user experience and rankings across search engines. When developing with Laravel, a PHP framework, you get features and techniques included in the framework to optimize your site for speed and efficacy. In this post we will discuss laravel optimization using effective caching strategies, efficient databases querying and lazy loading vs eager loading along with some other techniques to improve performance.

Caching Strategies

Caching is used to reduce the load on database and speed up the response. Laravel has many caching backends like Memcached and Redis. These are pretty straightforward to implement in Laravel.

// Cache a query result for 60 minutes
$posts = Cache::remember('posts', 60, function () {
    return Post::all();
});

This code checks for posts and if not then fetches them and adds them to cache for 60 minutes.

use Illuminate\Support\Facades\Cache;

$popularPosts = Cache::remember('popular_posts', 1440, function () {
    return Post::with('author', 'comments')
               ->where('views', '>', 1000)
               ->orderBy('views', 'DESC')
               ->take(10)
               ->get();
});

This query caches top 10 popular posts along with their associated authors and comments for 1440 minutes (24 hours). This query uses with to minimize the number of queries executed.

Database Query Writing for Laravel Optimization

We always try to improve our database queries but Laravel provides Eloquent ORM that makes it easy to write complex queries in simple way but it’s most important to know how to write an efficient query.

// Instead of fetching all columns, specify only the needed ones
$users = User::select('id', 'name', 'email')->get();

This query is small and specific and reduces the unnecessary load on database. It only fetches what’s needed.

$postsWithActiveAuthors = Post::whereHas('author', function ($query) {
    $query->where('active', 1);
})->get();

This snippet uses whereHas method to fetch the posts that have active authors (very useful). It makes the query efficient by avoiding loading all posts.

Lazy Loading vs Eager Loading

Laravel gives you options on how to load related models. Lazily which means that related models load on-demand and Eagerly that loads elated models all at once. Eager loading is most of the time the preferred way unless you have very specific case for Lazy loading.

// Lazy loading (inefficient)
$books = Book::all();
foreach ($books as $book) {
    echo $book->author->name;
}

// Eager loading (efficient)
$books = Book::with('author')->get();
foreach ($books as $book) {
    echo $book->author->name;
}

Eager loading fetches related models in single query and avoids the N+1 problem of lazy loading.

$users = User::all();
foreach ($users as $user) {
    // This will execute a new query for each user to get their posts
    foreach ($user->posts as $post) {
        echo $post->title;
    }
}

Inefficient: Here each user’s posts are not fetched untill they are accessed inside loop leading to multiple queries.

$users = User::with('posts')->get();
foreach ($users as $user) {
    // All posts are loaded along with users in a single query
    foreach ($user->posts as $post) {
        echo $post->title;
    }
}

Efficient: with('posts') ensures that all the posts are loaded in single query. It reduces the number query to just one making it more efficient.

Other Optimization Techniques

Implementing following Laravel optimization techniques also contribute in enhancing application performance significantly.

Optimize your assets:

Laravel Mix provides clean and fluent API for webpack build steps. We can use it to minify and combine CSS and JavaScript files. This reduces the number HTTP requests.

// webpack.mix.js
const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
   .minify('public/js/app.js');

mix.sass('resources/sass/app.scss', 'public/css')
   .minify('public/css/app.css');

This example compiles JS and SASS files and minifies them resulting in much smaller files and faster load time.

Database Indexing:

Use Index for columns that are frequently searched or used as foreign keys. This enhances database query performance and Index can be added via Migrations.

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('posts', function (Blueprint $table) {
    // Create an index for the 'title' column
    $table->index('title');
    
    // Create a unique index for the 'slug' column
    $table->unique('slug');
    
    // Foreign key index
    $table->foreign('user_id')->references('id')->on('users');
});

Route Caching:

Route caching increases website performance and especially if you have large number of routes.

php artisan route:cache

Here we create a route cache file for faster route registration. Note that any new route additions require running this command again.

Queue Workloads for laravel optimization:

For tasks that are time consuming, e.g. sending emails or some sort of image processing, it’s beneficial to run these tasks in background. Laravel’s queue system is designed to queue certain tasks and process them asynchronously.

First, generate a new job.

php artisan make:job ProcessImage

Next, add job’s behaviour

// app/Jobs/ProcessImage.php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessImage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $image;

    public function __construct($image)
    {
        $this->image = $image;
    }

    public function handle()
    {
        // Process the image here
    }
}

Now Dispatch the job.

ProcessImage::dispatch($image);

This snippet sends the image processing job to the default queue and Laravel handles the rest.

Wrapping Up

Optimizing a Laravel application involves a combination of caching strategies, efficient database operations, and smart loading of resources. By implementing these techniques, you can significantly reduce load times and resource usage, leading to a smoother user experience and potentially higher SEO rankings.

Here are some resources to dive deep in Laravel Optimization and Performance.

Laravel official documentation: https://laravel.com/docs/10.x/readme

Laracasts: https://laracasts.com/browse/all

See other posts related to Laravel here.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top