Developer focused load testing for Laravel Laravel

Testing your Laravel application is very different from testing a web server (e.g. nginx, apache). With an application you need to ensure you test the full stack, including the "heaviest" workloads like SQL, your job server, horizon and more.

Prefer to just sign up? Setup your test and run it in ~5 minutes.

Laravel Stress and Performance Testing

Test your whole Laravel stack

With an application you need to ensure you test the full stack, including the "heaviest" workloads. By examples these can include:

  1. Laravel (PHP) generated pages
  2. Executing queries, e.g. logging users in, running searches
  3. CRUD operations, especially Updates or Creates
  4. Job queues or servers like Horizon

These operations are interactive, dynamic content. With Laravel, they all require PHP processing, and often require a SQL database interaction or Redis cache.

These are the common bottlenecks in a modern web application. Server load testing is very different, and has to do with raw requests per second from the web server itself, e.g. Nginx, Apache, etc.

LoadForge is actually a Laravel application, so we are extremely familiar with scaling Laravel applications and APIs.

With LoadForge you can quickly scan your Laravel app, or record your browser actions, or even script your test in python.

We have loads of examples for Laravel, and you'll be able to load test your app in minutes.

Detailed Guide

Read our full Laravel load testing step-by-step guide below. We're available to assist on live chat or by contacting us whenever you need.

Breaking your Laravel app into components

You want to ensure your load testing attacks all the critical components of your application. Typically, this is three things:

  1. Static content (images, stylesheets, javascript)
  2. Dynamic content (pages, user profiles, etc)
  3. Database operations

In developing this strategy you'll want to determine the average wait time of a user of your service. Typically, a user waits on average between 5 and 9 seconds between webpages. So for each user we simulate we now know 1 dynamic page per 5-9 seconds.

You can also use our built in wizard to scan your Laravel app, or, use our browser recording feature to record your browsing and convert that to a test.

After that, we want to gauge how many static content items are returned by your average webpage. Browse a few with Chrome or Firefox Developer tools open and watch the bottom bar for the total requests per page, as seen in this screenshot:

Objects Per Page

As you can see above, we requested 19 objects. However, in our case many of those are not hosted on our system as we use a CDN. You can look at the domain to work out how many items hit your site. Lets assume that on average its 10 static content items (stylesheets, CSS, fonts, images).

The final component is to ensure that the dynamic pages you are visiting are causing database load. For example, make sure you are logging in. Adding items to carts. Searching, opening blog posts, etc. In total our plan has led to these decisions:

  1. We're going to request 1 dynamic page every 5-9 seconds
  2. For every dynamic page we will ask for 10 static content items
  3. We're going to use database-driven pages

Creating a test

LoadForge gives you the opportunity to design tests to suit your needs, like we've described above. You can also use the wizard to crawl your Laravel app and discover all the testable content.

We can now write our LoadForge test, which we will execute against our Laravel site we've defined above. We'll start by defining just the basics - the URL to run it against, and that we'll start with 500 simultaneous users. Remember that with our 5-9 seconds wait time decision that will be around 500/7 = 71 per second.

This is very easy to setup on LoadForge, and we have automated wizards. The next step is where we can customize, defining the locustfile. We'll show you our complete one, and then break it down:

from locust import HttpUser, task, between

class QuickstartUser(HttpUser):
    wait_time = between(5, 9)

    def laravel_page(self):
Let's break this down, it's quite similar to our default template, and if you want advanced uses check out our documentation. As you can see we've defined wait_time as between(5, 9) - between 5 and 9 seconds as discussed above. Next we have the laravel_page test, which is fetching simply /. We could add additional ones here as well. We're also using this to do the 3 static gets on our page.

Watching your Laravel system

The test will automatically help you to identify any errors, and scale your app. But, you can monitor these on your actual Laravel webserver:
  1. CPU usage
  2. SQL database load
  3. Redis (or other) load
  4. Memory usage
  5. Horizon/job queue status

Don't forget your webserver! Apache or Nginx are by default not set up for high scale. We have guides available for Nginx and PHP.

Tuning Laravel for high performance

There are a wide variety of activities you should undertake to improve and scale your Laravel app, as you learn about the bottlenecks by using LoadForge. Caching and optimizing your site and server can lead to huge improvements in Laravel performance, and efficient database usage is key.

Laravel Settings Caches

Considering caching your config, routes, and more for performance improvements:

php artisan config:cache
php artisan route:cache

Cache expensive queries

Laravel has an excellent caching system, and it's easy to wrap Eloquent or DB queries inside, as shown below:

# Cache the Posts::all() query for 60 minutes
$posts = Cache::remember('posts', 60*60, function() {
    return Posts::all();
This will store the results for 60 seconds, meaning you don't need to fetch them every time.

Tune your PHP and webserver

Make sure you read our guides on high performance Nginx and PHP-FPM:

  1. Webserver performance (see our nginx guide)
  2. PHP performance (see our PHP-FPM guide)

Eager load your requirements

Eager loading can reduce your queries from thousands to tens. When you use relationships on Eloquent models you should always be thinking of eager loading. We have a simple example of efficient vs inefficient loading below:

# 1 query for options for every item in questions
$questions = Questions::all();

foreach ($questions as $question){
    echo $question->option->count();

# 2 queries in total
$questions = Question::with('options')->get();

foreach ($questions as $question){
   echo $question->option->count();

Understanding results

Interpreting the results of your test are as important as running the test, if not more. Continue this on our reading load test results guide.

Beautiful, powerful reports, with actionable metrics

LoadForge automatically analyzes your site, explaining errors, showing detailed graphs, and performance numbers per page. Easily and quickly understand your load testing results.

  • Graphs for requests, errors, rates, latency, P95, P99
  • HTTP error analysis and performance AI
  • Download CSV or PDF reports
  • Store and compare your tests