Load Testing With Locust
Published: 1/10/2026 (Updated: 1/10/2026)
What is Load Testing?
Load testing is a form of performance testing that makes it easy to study and understand or evaluate how a system like a website, an API or even an application will behave under heavy load or real world usage.
For example, when we deploy an API, we are unable to properly estimate how our API will behave when "x" number of users start using it. We need to know this kind of information so as to properly provision resources (move to a server with better specifications) or even know the bottlenecks of our applications so we can work on making them better without degrading the service we are providing the user.
What is Locust?
Locust is an open source load testing tool used to define user behaviour with Python code, and swarm your system with millions of simultaneous users. Locust Documentation
Load Testing - Installation of Locust
You first need to create a directory for the load test and then create and activate your virtual environment. Then you can install locust:
uv add locust || pip install locust
Locustfile Creation
So to run our load tests we need a file with our test instances in it. We can create a locustfile.py in our project directory. We can add the following code to our locust file:
import time from locust import HttpUser, task, between class NormalUser(HttpUser): wait_time = between(1, 5) @task def get_products(self): self.client.get("/products") @task(3) def get_product_details(self): product_id = 1 self.client.get(f"/products/{product_id}") @task(2) def create_order(self): self.client.post("/orders", json={ "product_id": 1, "quantity": 2 })
Understanding the Locustfile
Let me break down what's happening in this code:
HttpUser Class: This is the base class that represents a user interacting with your system. Each simulated user will be an instance of this class.
wait_time: This defines the time each user waits between executing tasks. between(1, 5) means users will wait randomly between 1 and 5 seconds between requests, simulating real user behavior.
@task Decorator: Methods decorated with @task represent actions that users will perform. Locust will randomly pick tasks for each user to execute.
Task Weights: You can pass a number to the @task decorator (like @task(3)) to control how often a task is executed relative to others. Higher numbers mean the task runs more frequently.
self.client: This is an HTTP client that makes requests to your application. It automatically tracks response times and success/failure rates.
Running Your Load Test
Once you've created your locustfile, you can run it with:
locust -f locustfile.py --host=http://localhost:8000
Then open your browser and navigate to http://localhost:8089. You'll see the Locust web interface where you can:
- Set the number of users to simulate
- Set the spawn rate (how quickly users are added)
- Start and stop the test
- View real-time statistics and charts
Command Line Options
You can also run Locust in headless mode without the web interface:
locust -f locustfile.py --host=http://localhost:8000 --users 100 --spawn-rate 10 --run-time 5m --headless
This command will:
- Simulate 100 users
- Spawn 10 users per second
- Run for 5 minutes
- Run without the web UI
Advanced Features
Multiple User Types
You can define different user behaviors by creating multiple user classes:
from locust import HttpUser, task, between class BrowsingUser(HttpUser): weight = 3 wait_time = between(2, 5) @task def browse_products(self): self.client.get("/products") class PurchasingUser(HttpUser): weight = 1 wait_time = between(5, 10) @task def make_purchase(self): self.client.post("/checkout", json={"cart_id": 123})
The weight attribute determines the ratio of each user type. Here, 75% will be browsing users and 25% will be purchasing users.
Authentication
For testing authenticated endpoints:
class AuthenticatedUser(HttpUser): def on_start(self): # This runs once when each user starts response = self.client.post("/login", json={ "username": "test_user", "password": "password123" }) self.token = response.json()["token"] @task def access_protected_resource(self): self.client.get("/profile", headers={ "Authorization": f"Bearer {self.token}" })
Analyzing Results
Locust provides several metrics to help you understand your system's performance:
- Request count: Total number of requests made
- Failure rate: Percentage of failed requests
- Response times: Min, max, average, and percentiles (50th, 95th, 99th)
- Requests per second: Throughput of your system
- Response time charts: Visual representation of performance over time
Best Practices
- Start small: Begin with a low number of users and gradually increase to find your system's breaking point
- Realistic use cases: Model your tests after actual user behavior patterns
- Monitor your system: Use tools like monitoring dashboards alongside Locust to see CPU, memory, and database metrics