- Four different test shapes answer four different questions: load (does it meet target?), stress (where does it break?), spike (does it survive a sudden surge?) and endurance (does it leak?).
- Report p95 and p99 latency, never the average — an average of 250ms can hide one user in twenty waiting four seconds.
- The useful output of a load test is not pass/fail but the knee point: the concurrency where latency starts rising faster than throughput.
- Derive concurrency from real traffic logs, then test at 1×, 2× and 5× peak.
What is API load testing?
Load testing measures how an API behaves under concurrent traffic — how latency, throughput and error rate move as the number of simultaneous users rises. It answers a question functional testing cannot: the endpoint works, but does it still work when two thousand people call it at once?
The failure mode it catches is specific and common. A service that responds in 40 milliseconds for a single caller can take four seconds at a hundred concurrent callers, because a connection pool, a thread pool, a database lock or a downstream rate limit saturates. Nothing in the code changed; only the arrival rate did.
The four test shapes
| Test | Traffic profile | What it finds | Typical duration |
|---|---|---|---|
| Load | Steady, at expected peak | Whether you meet your latency and error targets | 10–30 minutes |
| Stress | Ramping until failure | The breaking point and how it fails | 20–60 minutes |
| Spike | Instant jump, then drop | Elasticity, cold starts, autoscaling lag | 5–15 minutes |
| Endurance | Moderate, sustained for hours | Memory leaks, pool exhaustion, log-disk growth | 2–24 hours |
Load testing
Hold traffic steady at the level you expect at peak and confirm the system meets its targets. This is the baseline test: it should pass. If it doesn't, nothing further is worth measuring until it does.
Stress testing
Ramp concurrency past the expected peak until something gives. The point is not to survive but to learn how it fails. A system that sheds load cleanly with 503s and a Retry-After header is in far better shape than one that accepts every request and times out on all of them.
Spike testing
Jump from near-idle to very high traffic in seconds. This is what a marketing email, a product launch or a link on a popular aggregator actually looks like. Spike tests expose cold-start latency in serverless functions and the lag between an autoscaler noticing load and capacity arriving — often 60 to 300 seconds, during which the existing instances absorb everything.
Endurance testing
Hold a moderate, comfortable load for hours. Defects here are slow: a heap that grows a few megabytes per thousand requests, database connections that are never returned to the pool, log files filling a disk. None of these appear in a 15-minute run, and all of them cause 3am incidents.
Why p95 and p99 beat the average
Consider a hundred requests: ninety-five return in 50ms, five take 4 seconds. The mean is roughly 250ms, which looks healthy on a dashboard. But one user in twenty waited four seconds, and those are the users who complain, abandon carts and retry — adding yet more load.
Percentiles describe experiences; averages describe arithmetic. The p99 is the number that corresponds to your worst customer experience, and it is where queueing, garbage collection pauses and lock contention show up first.
Track the full distribution: p50 for the typical case, p95 for the edge of normal, p99 for the tail. A p50 that stays flat while the p99 quadruples is the signature of a resource beginning to saturate — the earliest warning you will get.
Choosing concurrency
Round numbers like "test with 1000 users" are arbitrary. Derive the figure instead:
- Take peak requests per second from your access logs — the busiest minute of the busiest day in the last month.
- Test at 1× that rate to establish the baseline and confirm you meet targets today.
- Test at 2× to cover ordinary growth and campaign traffic.
- Test at 5× to find the knee point and know the headroom you actually have.
Include realistic think time between requests. A test that hammers an endpoint with zero delay produces a traffic pattern no real client generates, and usually measures your load generator rather than your API.
Reading the results
Three curves matter, and their relationship tells the story:
- Throughput vs concurrency — should rise linearly, then flatten. The point it flattens is saturation.
- Latency vs concurrency — should stay flat while throughput rises. The point it starts climbing is the knee.
- Error rate vs concurrency — should stay at zero until well past the knee. Errors appearing before the knee indicate a limit unrelated to capacity, such as a rate limiter or connection cap.
Beyond the knee, added concurrency buys nothing but latency: requests queue rather than execute. Capacity planning targets a comfortable margin below that point, not the maximum the system can technically survive.
Common load testing mistakes
- Testing from one machine. Your load generator saturates its own CPU or network before the API does, and you measure the generator.
- Ignoring the error rate. Throughput that includes a 40% failure rate isn't throughput.
- Testing an empty database. Query plans that are instant across a thousand rows behave differently across ten million.
- Caching everything accidentally. Requesting the same resource repeatedly measures your cache, not your API. Vary the parameters.
- Running once before launch. Performance regresses continuously. A scheduled run catches the release that doubled a query count.
Load test your API without writing a script
Paste a URL. Flasqo discovers your endpoints, generates the suite and runs it — free, no credit card.
Start testing free