Guides

How to run a load test: a step-by-step guide

6 min read

To run a load test, decide what a good result looks like, script one realistic user journey, check that script with a single user, then increase the load in steps while you watch response times and errors. Compare what you measured with the goal you set at the start, and change one thing at a time before the next run.

StepWhat you doDone when
1. Set the goalPick the load to test for and the numbers that count as a passYou can write the pass criteria in one sentence
2. Script a journeyTurn one real user path into a scriptThe script runs without errors
3. Smoke testRun it with one virtual userEvery check passes
4. Ramp upIncrease the load in steps and hold at the targetYou reach the target or a stop condition
5. Read the resultsCompare percentiles and errors with the goalYou know whether it passed and what to change

What should you decide before running a load test?

Decide what load you are testing for and what result counts as a pass. Without both, a load test produces numbers but no answer.

Start from real traffic if you have it. Your analytics or access logs tell you the busiest hour, its requests per second and which endpoints take most of them. Set the target above that peak, because the point is to know you have headroom. Then write the pass criteria as numbers, for example: the 95th percentile response time stays under 500 ms and fewer than 1% of requests fail at 200 virtual users.

Two practical decisions belong here too. Pick an environment that looks like production in size and configuration, because a staging server with a quarter of the capacity tells you little about production. And make sure you have permission to test it: load testing a system you do not own, or one shared with other teams, without telling them can look exactly like an attack.

How do you script a realistic user journey?

Script the path that matters most to the business, one step at a time, with pauses where a real person would read or type. A script that hits one URL as fast as it can measures something, but rarely the thing you care about.

For a shop: open the home page, search, open a product, add it to the cart. For an API: log in, list items, fetch one item. Add a short pause between steps (think time), use varied test data so caches behave the way they do in real life, and add a check on each response so a page of errors cannot pass as a fast response.

Here is the script we used for the example run in this guide, written for k6. It ramps up to 10 virtual users, holds, and ramps down, with two pass criteria built in:

import http from "k6/http";
import { check, sleep } from "k6";

export const options = {
  stages: [
    { duration: "10s", target: 10 },
    { duration: "20s", target: 10 },
    { duration: "5s", target: 0 },
  ],
  thresholds: {
    http_req_duration: ["p(95)<500"],
    http_req_failed: ["rate<0.01"],
  },
};

export default function () {
  const res = http.get("http://127.0.0.1:8765/");
  check(res, { "status is 200": (r) => r.status === 200 });
  sleep(1);
}

A real journey has several requests and real URLs. This one stays tiny so the steps are easy to follow.

Why run a single-user smoke test first?

A smoke test with one virtual user proves the script works before you put real load on anything. It is the cheapest way to catch a wrong URL, a missing login token or a check that always fails.

With k6 you can override the load from the command line, so the same script runs once with a single user:

k6 run --vus 1 --iterations 1 script.js

When we ran it, the single check passed, so the script was ready for load. If a check fails at this stage, fix the script before going further: errors at one user turn into noise at a hundred.

How should you ramp up the load?

Increase the load in steps and hold each step long enough to settle, instead of jumping straight to the target. A step-wise ramp shows you the level at which things start to degrade.

A common shape is to ramp up to a first step, hold for a few minutes, ramp to the next step, hold again, and so on up to the target, then ramp down. Watching each hold separately tells you whether response times climb smoothly with load or stay flat and then jump. That jump, the point where every extra user makes every request slower, is the most useful thing a load test can find. Our example holds 10 users for 20 seconds: enough to show the stages, far too short for a real test.

What should you watch while the test runs?

Watch response time percentiles, the error rate and the throughput on the load generator side, and CPU, memory and database load on the system under test. The first three tell you how users would feel, and the last three tell you why.

Agree on stop conditions before you start, for example: stop if the error rate passes 5% or response times pass several seconds. Pushing a system that has already fallen over teaches nothing, and on a shared environment it gets in other people’s way.

Watch the load generator too. If it is at full CPU, the slow responses may come from your own laptop rather than the server.

How do you read the results of a load test?

Read the percentiles and the error rate against the pass criteria you wrote down at the start. The average response time is the least useful number in the report.

Here is what our example run reported (35 seconds, up to 10 virtual users, a small static page served on a laptop, run on 8 October 2026):

MetricValue
Requests282 (8 per second)
Failed requests0%
Average response time0.69 ms
90th percentile0.66 ms
95th percentile0.71 ms
99th percentile2.68 ms
Slowest request15.98 ms
ThresholdsBoth passed

The numbers are tiny because the target was a static file on the same machine, so they are no benchmark. The shape is the lesson: the average came out higher than the 90th percentile, because a handful of slow requests pulled it up. Percentiles describe what most requests experienced, and the 99th percentile and the slowest request show the tail that a few users hit. Judge the run on the percentile in your pass criteria, and use the tail to decide whether something needs a closer look.

If a run misses its goal, change one thing (a query, a cache setting, an instance size) and run the same test again, so you know what made the difference.

When should you run the test from the cloud?

Move the load generator to the cloud when one machine cannot produce the load you need, or when it matters where your users are. A laptop on office Wi-Fi measures your office connection as much as your server.

The same k6 script can run on infrastructure you manage, on Grafana’s hosted service, or on LoadFocus, which runs k6 scripts from 25 cloud regions. Its reports break results down by location and plot response time against the number of virtual users, which is where the jump described above becomes visible (how to read LoadFocus results).

FAQ

How long should a load test run? Long enough to hold the target load for several minutes after the ramp-up, so short spikes do not decide the result. Holding for at least 10 minutes is a sensible start, and much longer when you are looking for memory leaks or slow degradation.

How many virtual users do I need? Work it out from real traffic. Take the busiest hour’s requests per second, estimate how many requests one user journey makes and how long it takes, and size the virtual users so the test produces that rate with some headroom on top.

Is it safe to load test production? It can be, with care: test at a quiet time, tell the people who run the system, set stop conditions and start well below the expected peak. Many teams prefer a production-sized staging environment, so a failed test cannot affect customers.


The technical claims in this article have not been independently reviewed.

LoadFocus team
Written by the LoadFocus team, the people behind a cloud load testing service.