Product documentation
Updated September 27, 2026

Performance Testing: Load, Stress, Spike, Soak and More

A functional test tells you whether your API gives the right answer. A performance test tells you whether it still gives that answer, fast enough, when many people use it at once.

View as Markdown

Applies to: Professional, Trial and Enterprise editions (Free shows a preview only) · Web app and Desktop app · Designing a test needs permission to create or edit tests; starting one needs permission to run tests

Overview

A functional test tells you whether your API gives the right answer. A performance test tells you whether it still gives that answer, fast enough, when many people use it at once. Shift-Left Studio's performance testing sends many requests to your API at the same time, the way real traffic would, and reports whether the API keeps up.

You do not write a new script to do this. A performance test is built from the tests you already have in your project. You pick the tests, choose how much traffic to send and for how long, say what "good" means (for example, "95% of requests answer in under 800 ms"), and run it. Every request is built exactly the way a functional run builds it, with the same authentication, headers and body.

The report leads with a verdict in plain words, such as "All 2 targets met during the hold at 212 requests/s", and then shows the figures behind it: percentiles, throughput, errors grouped by cause, and where the time was spent.

You find everything under Performance in the top toolbar (the lightning-bolt button). Everything in it belongs to a project.

Key concepts

TermWhat it means
Scenario (performance test)A saved design: which tests run, how much load, for how long, against which environment, and which targets decide pass or fail.
RunOne execution of a scenario. Each run has its own report.
Virtual userA simulated person. Each virtual user sends a request, waits for the answer, optionally pauses, and repeats.
Requests per secondA fixed rate of new requests, sent on schedule whether or not the API has answered earlier ones.
WorkloadA group of virtual users doing the same thing, for example "browse" or "checkout". A scenario can mix several workloads by share.
StageOne part of the load profile: a duration and a target number of users or requests per second.
HoldThe steady stage of a test. Targets are judged on the hold, not on warm-up or ramp-down.
ThresholdA target inside a scenario, such as "p95 latency during the hold < 800 ms".
Performance target (SLO)A project-level objective, such as "Checkout p95 under 800 ms and errors under 1%". It is checked continuously against ordinary test runs, and can also be judged inside a load test.
p95The response time that 95 of every 100 requests were faster than.
Load generatorThe machine that sends the load: the Studio server, or a load agent.
Load agentAn extra machine that takes an equal share of a run, for more load or load from several places.

The kinds of performance test

When you create a performance test, the first question is What should this test find out? Each kind answers a different question and starts from a sensible profile that you can change.

KindThe question it answersHow the load is appliedMeasured as
SmokeDoes the scenario run at all, and what does normal look like?One user for one minute.A fixed number of users
LoadDo you meet your targets on a normal busy day?Ramp up to your expected users over one minute, hold for several minutes (five by default), then ramp down. Targets are judged during the hold.A fixed number of users
StressWhere do the targets break, and how does it fail?Four steps of two minutes each: half, one, one and a half, and twice your expected request rate.A fixed rate of requests
SpikeDoes it survive a sudden burst, and how fast does it recover?Low normal traffic for two minutes, a jump to twice your expected rate for one minute, then back to normal for three minutes.A fixed rate of requests
SoakDoes it slowly get worse over hours: memory, connections, latency creep?Ramp up, hold your expected users for at least one hour, then ramp down.A fixed number of users
BreakpointWhat is the most it can handle?Twelve one-minute steps, each a quarter of your expected rate higher than the last. The run stops itself once your targets fail for long enough.A fixed rate of requests
ConcurrencyDo identical requests at the same instant cause duplicates, conflicts or races?All users start at once and run the journey one time.A fixed number of users
Rate-limit probeIs the documented rate limit the real one?The rate of one request climbs to four times your expected rate over two minutes, until the API answers 429 Too Many Requests.A fixed rate of requests
CustomYour own question.Your own stages, model and targets.Your choice

Users or requests per second — why it matters

Studio picks the right model for each kind, and you can change it on the Load profile step under How the load is expressed.

  • A fixed number of users (load, soak, concurrency, smoke). Each virtual user waits for an answer before its next step. This is what that many people at once would experience.
  • A fixed rate of requests (stress, spike, breakpoint, rate-limit probe). New requests keep arriving on schedule even when the API slows down. With a fixed number of users, a slow API quietly receives fewer requests, which hides the very problem those tests exist to find.

What each kind adds to the report

Each kind adds the analysis it exists for:

  • Stress and breakpoint draw a capacity curve (response time and errors against the rate achieved), mark the point where response times start to climb steeply, and show the last stage at which every target still held.
  • Spike measures how long the API took to get back to within 10% of its pre-spike p95. If the profile is too short to measure recovery, the report says why rather than leaving the section blank.
  • Soak measures drift: how much p95 and the error rate grew per hour during the hold. By default it is called drifting when p95 grows by more than 10% of its starting value per hour.
  • Concurrency shows the mix of outcomes for identical requests: successes, conflicts (409/412/423) and server errors. Mixed outcomes suggest a race.
  • Rate-limit probe shows whether a 429 arrived and at what rate.

How a performance test is built from your tests

A performance test does not copy your tests. It reads them when the run starts and builds each request with the same code a functional run uses. That means:

  • The environment's base URL, variables and authentication are applied exactly as in a functional run. There is no separate authentication setting for load tests; the environment you choose decides it.
  • A value one step saves, such as an order id, is passed to the next step, exactly as in a workflow.
  • You can bind a data set so each virtual user sends different values.
  • You can use a whole workflow as a workload. Its calls run in order for every virtual user, with its extractions and wiring. Conditional and script blocks cannot run under load; the dry run names any it finds.
  • Every response's status is checked. A share of responses (you choose how many) also runs the test's other assertions.

A few things run once per run rather than before every request, and the report tells you when this happens: a pre-request script, a signed request, and a WS-Security header on a SOAP call.

Protocols

ProtocolLoad-testable?Notes
RESTYes
SOAPYesThe envelope is built once by Studio's SOAP client, then sent under load with each user's values filled in. Values are not read out of SOAP responses between steps under load; the report warns you if a test relies on that.
GraphQLYesA GraphQL error inside a successful HTTP reply counts as an error.
JSON-RPC 2.0Yes (Trial and Enterprise, as for functional tests)A JSON-RPC error inside a successful HTTP reply counts as an error.
MCP server endpointsNoEach virtual user would need its own held session, which is a different kind of test.
WebSocket-RPCNoA WebSocket call is a held connection, not a request.

Where the load comes from

The Studio server (default)

By default the load is sent from the machine running Studio: the server for the web app, or your own computer for the desktop app. The load is generated in a separate process, so the rest of Studio stays responsive while a test runs.

One ordinary machine can usually send a few thousand requests per second. The report watches the load generator itself. If it ran out of CPU, its measurements describe that machine, not your API, and the report says so first and marks the verdict Inconclusive.

Load agents (distributed load)

When one machine is not enough, or you want load from several places, you can add load agents. A load agent is the Studio local runner started in agent mode on another machine. It takes an equal share of a run.

  • Agents connect out to Studio, asking for work every few seconds. Nothing needs to be opened on the agent machine's firewall.
  • Each generator runs the same profile at its share of the users or rate, with its own share of the data rows, so two generators never send the same unique row.
  • All generators start at the same moment, and their measurements are merged exactly into one report.
  • If an agent stops reporting, the report names it, and the verdict becomes Inconclusive because less load was sent than planned.

Registering a load agent is for Administrators only, because an agent receives the credentials its share of the run needs. A scenario that authenticates with a client certificate always runs from the server only; its private key is never sent to another machine. See Create and Run a Performance Test for setup.

Safety built in

Sending load to a system is a deliberate act, so Studio adds several guards:

  • You confirm you are authorised to send load to a project's environments the first time you run on that project. This is recorded with your name.
  • Production is locked. A production environment is refused unless an Administrator has allowed load testing on it. Even then, the person starting the run must type the environment's name to confirm.
  • A check before load. One request per step is sent first. If the environment is down or a test is misconfigured, the run is refused with the reason, and no load is sent.
  • Automatic stop. By default a run stops itself if more than half of its requests fail for ten seconds, so a broken environment is not hammered for an hour.
  • Nothing is sent by a dry run. The dry run builds the plan exactly as a real run would and shows you what would be sent.

Editions

EditionWhat you get
FreeA preview of the Performance screens with example data. Runs are not included.
ProfessionalUp to 100 virtual users (or requests in flight) per load generator, runs of up to 15 minutes, one run at a time. No load agents.
Trial and EnterpriseUp to 2,000 virtual users (or requests in flight) per load generator, runs of up to 12 hours, two runs at a time, and any number of load agents.

The limit applies per load generator. A run split across load agents can send more in total, because each generator carries its own share. When a profile goes over your edition's limit, the designer says so on the field and the run is refused until the profile fits; nothing is silently reduced.

Before you begin

  • A project with tests (REST, SOAP, GraphQL or JSON-RPC) that pass in a functional run.
  • An environment for the project with a base URL and working authentication.
  • A test environment you are allowed to put load on. Never point a load test at a system you do not own or have permission to test.
  • For load agents: an Administrator, and a Trial or Enterprise licence.

Best practices

  • Start with a smoke test. It confirms the scenario runs and shows what normal looks like before you add real load.
  • Test in a production-like environment, not on a shared development server where other people's work distorts the figures.
  • Use data sets for anything that creates records. Use the "each row used once" mode so users do not collide on the same data.
  • Watch the generator. If the report says the load generator was overloaded, lower the load or add load agents before trusting the numbers.
  • Set a baseline once you have a run you trust, so later runs are compared against it.
  • Define project performance targets so you get a continuous signal from your everyday functional runs, not only when you run a load test.

FAQ

Is this a browser or page-load test? No. It measures your API only.

Does it measure my servers' CPU and memory? No. It measures what the API does from the outside. You can add monitoring links (for example, a Grafana dashboard) to an environment, and each report links to them for the same time window.

Do performance runs affect my functional pass rates? No. A load run is thousands of requests judged against targets, not one pass or fail per test, so it is kept out of the functional run summaries and charts. Performance runs have their own history.

Can an AI agent start a load test? The project assistant can offer to create a scenario or start a run, but nothing happens until you accept its offer. AI coding agents connected through the MCP server can read load runs and reports but cannot start a load test. Sending sustained load stays a deliberate act by a person.

Can I run it from CI? Yes. See "Automating this" in Create and Run a Performance Test.

For administrators (self-hosted installations)

SettingDefaultWhat switching it does
LOAD_DISTRIBUTED_AGENTS_ENABLEDonfalse hides load agents on this installation; every scenario runs from the server only.
LOAD_REPORT_NARRATIVE_ENABLEDonfalse removes the short written summary from reports. The summary also needs an AI provider to be configured.

In a deployment with several API servers behind a load balancer, load agents must reach the server that started the run. Configure session affinity for the path /api/performance/agent/.

Related articles

Next steps

Still stuck?

Tell us what you’re trying to accomplish and we’ll point you to the right setup—installation, auth, or CI/CD wiring.