You already know what load testing is. This is the part where you actually run one. The plan is short: pick a flow, set a target, script it, ramp the load, and read the right numbers. The trap is everywhere else. Most load tests fail not because the tooling is hard but because the flow is unrealistic, the target is vague, or someone reports the average and calls it a day. Here is how to run one that tells you something true. For the wider map of performance test types, see performance testing.
1. Pick one critical flow#
Do not try to load test "the app." Pick a single path that matters and that breaks the business if it gets slow: login, search, add-to-cart, or checkout. One flow, scripted well, beats ten flows scripted badly. You can always add more later, but the first useful result comes from going deep on one.
2. Define a target#
A load test without a target is just traffic generation. Write a concrete pass condition before you run anything:
p95 response time under 500ms at 200 concurrent users, with an error rate below 1%.
That sentence has all four parts that matter: the metric (p95 response time), the threshold (500ms), the load (200 concurrent users), and the failure budget (under 1% errors). Now the test has a verdict instead of a vibe. Pull the numbers from real traffic or a realistic launch estimate, not from a round number that feels impressive.
3. Choose a load tool#
Any tool that can script your flow and report percentiles will do. Common open-source choices are k6, Gatling, and Locust; managed services wrap the same idea. The non-negotiable feature is percentile reporting. If a tool only gives you averages, it cannot answer the question you are asking, so skip it.
4. Script the flow#
Encode what a real user actually does, not a single bare request. That means the full sequence (open page, authenticate, submit), realistic think time between steps, and varied input data so you are not hammering one cached row. A script that logs in as the same user 200 times measures your cache, not your system. The closer the script and the environment are to production, the more you can trust the result.
5. Run a baseline, then ramp#
Run a small, steady load first, maybe 10 users, to confirm the script works end to end and the numbers look sane. This baseline is your reference point. Then ramp up in stages toward your target concurrency rather than slamming straight to 200. A staged ramp shows you the level at which response time starts to bend upward, which is far more useful than a single pass or fail at the top number.
How to read the results#
This is where most load tests go wrong, so read carefully.
Ignore the average. An average response time of 200ms can hide the fact that one user in twenty waited four seconds. The average smooths the slow requests into invisibility, and the slow requests are exactly the ones users complain about.
Read the tail percentiles instead:
- p95 means 95% of requests were faster than this number and 5% were slower. It is the standard headline metric for "how does this feel under load."
- p99 captures the worst 1%. It surfaces the stalls, timeouts, and garbage-collection pauses that p95 can still smooth over. At scale, 1% of requests is a lot of unhappy people.
- Throughput is requests handled per second. It tells you capacity, but on its own it lies: a system can hold high throughput while a slice of users waits seconds. Always read it alongside the percentiles.
- Error rate under load. Watch for it climbing as concurrency rises, which usually means something is saturating (a connection pool, a queue, a downstream dependency).
Compare all of this against the target from step 2. If p95 is 480ms at 200 users, you passed. If it is 1,200ms, you have a number to chase.
Find the first bottleneck#
When the target fails, do not optimize everywhere. Find the component that gives out first. Watch resource usage during the run: CPU, memory, database connections, and the slowest endpoints in your traces. One thing almost always saturates before the rest, and it is usually a database query, a connection pool ceiling, or a single slow endpoint dragging the percentile up. Fix that one thing, rerun the exact same test, and see how far the ceiling moved. Then repeat. Load testing is a loop, not a one-shot.
Common mistakes#
- Reporting the average. Covered above, and worth repeating, because it is the single most common way a load test lies.
- An unrealistic script. Same user, no think time, one data row. You end up testing your cache and feeling great about a result that will not survive real traffic.
- No target. Without a pass condition, every result is "interesting" and none is actionable.
- Testing against a tiny environment. A load test on a half-sized staging box invents bottlenecks that do not exist in production and hides ones that do.
- Skipping the baseline. If you ramp straight to peak and it fails, you cannot tell whether the script is broken or the system is.
- Treating one run as the truth. Numbers vary. Run it more than once before you trust a verdict.
Run it, then keep watching#
A load test answers one question at one moment: can this flow hold up to the load you threw at it, here, today. That is exactly what you want before a release, because it finds the ceiling while you can still raise it. What it cannot tell you is how that flow performs next month, after three deploys, from a user two continents away.
That gap is the difference between testing and monitoring. ObserveOne closes it on the monitoring side: it runs your critical flows continuously from multiple regions and tracks real response time over days and weeks, so the gradual slowdown a one-off load test never sees shows up as a trend before users feel it. Load testing finds the ceiling before release. ObserveOne watches where you actually are after it.