Load Test Report Template

A load test report should let a reader make a decision in 30 seconds and audit it in 10 minutes. Put the verdict first (pass, fail or pass with conditions, at what load), then the test configuration, a results-vs-thresholds table, the handful of charts that prove it, the bottlenecks found with evidence, recommendations with owners, and raw data in an appendix. Below is each section with a filled-in example for a fictional service, followed by a blank Markdown template you can copy.
"Larkspur Search API" is a fictional service. Every number in the example sections is illustrative, chosen to show how a section should read. None of it is a benchmark of any real system.
Report vs plan: what this document is for
The load test plan is written before the test and says what you will do and what counts as a pass. The report is written after and says what happened, whether it passed, why, and what to do next. The report should reference the plan rather than repeat it.
| Load test plan | Load test report | |
|---|---|---|
| Written | Before the test | Within a day or two after |
| Main reader | Engineers running the test, approvers | Decision makers, then engineers fixing issues |
| Core content | Workload model, thresholds, environment, risks | Verdict, measured results, bottlenecks, actions |
| Numbers | Targets and forecasts | Measurements, with run IDs and time windows |
| Ends with | Sign-off to run | Recommendations with owners and a re-test date |
Report structure at a glance
| # | Section | Question it answers | Typical length |
|---|---|---|---|
| 1 | Summary and verdict | Can we ship / handle the event, and at what load? | One paragraph |
| 2 | Test configuration | What exactly was tested, how? | One table |
| 3 | Results vs thresholds | Which criteria passed and failed? | One table |
| 4 | Charts | Where is the evidence? | 3 to 5 charts |
| 5 | Bottlenecks found | What limits capacity, and how do we know? | One short block each |
| 6 | Recommendations | What do we do, who does it, by when? | One table |
| 7 | Appendix | Can someone reproduce or audit this? | As long as needed |
1. Summary and verdict
Write this last, put it first. It needs five things: the verdict, the load it applies to, the headline numbers against target, the main risk, and the decision you are asking for. Avoid "the system performed well"; give the numbers.
Example:
Verdict: PASS WITH CONDITIONS at 600 RPS. Larkspur Search API met all thresholds at the 600 RPS target (forecast peak 400 RPS × 1.5): p95 240 ms (target < 300 ms), p99 690 ms (< 800 ms), errors 0.08% (< 0.5%). Capacity ends at about 700 RPS, where search-cluster CPU saturates and p95 exceeds 1 second. Risk: a peak 75% above forecast degrades search sharply. Condition: add one search node and raise the app pool limit before the 14 November launch (owners below), then re-test at 800 RPS.
Verdict wording should be one of three fixed values, so reports are comparable over time: PASS, FAIL, or PASS WITH CONDITIONS. If you use the third, the conditions must be specific actions with owners.
2. Test configuration
Enough detail for someone to re-run the same test, and to judge whether the environment matches production. Link the plan for the reasoning; record here what actually ran, including deviations.
| Item | Example value |
|---|---|
| Plan reference | Larkspur load test plan v1.2 |
| Build / version | search-api 3.8.0 (commit a1b2c3d) |
| Environment | Staging, production-sized: 6 app pods (2 vCPU each), 3-node search cluster, same instance types as production |
| Data | Production index snapshot, 41 M documents; query list sampled from 7 days of logs |
| Workload model | Open (arrival rate). Mix: 70% search, 20% autocomplete, 10% document fetch |
| Load profile | Steps of 200, 400, 600, 800 RPS, 5 min each, 1-min ramps; warmup 2 min at 100 RPS excluded |
| Thresholds | p95 < 300 ms, p99 < 800 ms, error rate < 0.5%, per step |
| Run date and window | 2026-10-21, 14:00–14:28 UTC |
| Deviations from plan | Soak test postponed; recommendation cache disabled by a config error in the first run (run discarded, see appendix) |
The "deviations" row matters. A report that silently differs from its plan is how wrong conclusions survive review.
3. Results vs thresholds
One row per load level (or per scenario), one column per threshold, and a clear pass/fail per cell. Use steady-state windows only; exclude ramps and warmup, and say so in the table caption.
Example (steady-state minutes of each step, warmup excluded):
| Step | Achieved RPS | p50 | p95 (< 300 ms) | p99 (< 800 ms) | Errors (< 0.5%) | Result |
|---|---|---|---|---|---|---|
| 200 RPS | 200 | 48 ms | 110 ms | 260 ms | 0.01% | PASS |
| 400 RPS | 400 | 55 ms | 150 ms | 380 ms | 0.02% | PASS |
| 600 RPS (target) | 599 | 71 ms | 240 ms | 690 ms | 0.08% | PASS |
| 800 RPS | 742 | 520 ms | 1,450 ms | 3,900 ms | 2.3% | FAIL |
Always show achieved RPS next to target RPS. At the 800 RPS step the system only absorbed 742, which is itself a capacity signal, and a sign that a closed-model test would have hidden the problem. The guide to reading load test results covers what to look for in each column.
If you track a single summary number for stakeholders, Apdex is a common choice; compute it with the Apdex calculator and state T next to it.
4. Charts to include
Include charts that prove the table, not every chart the tool produces. Every chart needs the same time axis, the step boundaries marked, and a one-line caption saying what to notice.
- RPS over time, target vs achieved. Shows the load was actually applied. Caption example: "Achieved RPS tracks target to 600, flattens at about 740 in the 800 step."
- Latency percentiles over time (p50, p95, p99). The core evidence. Mark the thresholds as horizontal lines. Caption: "p95 crosses 300 ms 40 seconds into the 800 RPS step."
- Error rate over time, split by status code. 5xx vs timeouts vs 429 tell different stories.
- The saturated resource. Whatever the bottleneck section names: CPU of the search nodes, connection pool pending count, queue depth. Same time axis.
- Comparison with the baseline run, if one exists: same percentiles for the previous release at the same load. See performance regression testing.
Avoid averages-only latency charts and charts with auto-scaled axes that make a 5 ms change look like a cliff. Charts exported as images should be readable without zooming at the page width the report will be read at.
5. Bottlenecks found
For each bottleneck give the symptom, the evidence, the cause (or best hypothesis, labeled as such) and the impact in load terms. Evidence means a metric and a time, not an impression.
Example, bottleneck 1: search cluster CPU.
- Symptom: p95 rises from 240 ms to 1,450 ms between the 600 and 800 RPS steps; achieved RPS stalls at 742.
- Evidence: search node CPU 61% average at 600 RPS, 92–97% from 14:22 UTC in the 800 step; search thread pool queue grows from under 5 to over 400 in the same minute.
- Cause: the search cluster has no headroom above about 700 RPS with this query mix. Autocomplete queries are 20% of requests but about half of search CPU time (from slow-log sampling).
- Impact: capacity ceiling about 700 RPS, 17% above target.
Example, bottleneck 2: app connection pool to the search cluster.
- Symptom: 2.3% errors at 800 RPS, almost all "pool acquire timeout" in app logs.
- Evidence: pool active at its limit of 20 per pod from 14:22 UTC; pending peaks at 85.
- Cause: secondary. The pool fills because search calls slow down (bottleneck 1); a larger pool alone would add load to an already saturated cluster.
- Impact: converts slowness into errors above about 700 RPS.
Distinguish the primary limit from its knock-on effects. Fixing a symptom, such as raising a pool size, without fixing the cause usually moves the failure rather than removing it. The connection pool exhausted guide covers that pattern.
6. Recommendations
Each recommendation needs an owner, a priority tied to the verdict, an expected effect, and how you will verify it. "Optimize queries" is not a recommendation; "cache autocomplete prefixes for 60 seconds, expected to cut search CPU by about a third, verify by re-test at 800 RPS" is.
| # | Action | Priority | Owner | Expected effect | Verify by |
|---|---|---|---|---|---|
| R1 | Add a fourth search node | Before launch | Platform team | Ceiling from about 700 to about 900 RPS | Re-test at 800 RPS |
| R2 | Cache autocomplete prefixes for 60 s | Before launch | Search team | Lower search CPU per request | Re-test; compare CPU per RPS with this run |
| R3 | Return 503 with Retry-After when pool pending > 50, instead of waiting | Next sprint | API team | Fail fast under overload, protect latency for admitted requests | Stress test above ceiling |
| R4 | Run the postponed 2-hour soak at 400 RPS | Before launch | QA | Detect leaks and slow growth | Soak report |
End the section with the re-test date. A report without one tends to be the last word on the subject until production writes the next one.
7. Appendix
Everything a skeptical reader needs to check your work:
- Run IDs or links to the raw results for every run, including discarded ones and why they were discarded. In LoadTester, a shareable public result link plus the PDF and CSV exports covers this.
- Full percentile tables per endpoint, not only the aggregate.
- The exact test script or scenario definition, and the version of the tool that ran it.
- Infrastructure configuration at test time: instance counts, autoscaling settings, pool sizes, relevant timeouts.
- Monitoring dashboard links with the time window pinned.
- Load generator health: confirmation that the generators were not the bottleneck.
- Known limitations, such as caches warmer than production or third-party calls stubbed.
Copyable Markdown template
Paste this into your wiki, repository or ticket and replace the brackets. It mirrors the sections above.
# Load Test Report: [service / feature]
Date of test: [YYYY-MM-DD] | Author: [name] | Plan: [link to plan, version]
Run IDs / result links: [ ... ]
## 1. Summary and verdict
**Verdict: [PASS | FAIL | PASS WITH CONDITIONS] at [N] RPS.**
[Service] [met / did not meet] thresholds at [N] RPS ([forecast] x [headroom]):
p95 [x] ms (target < [y]), p99 [x] ms (< [y]), errors [x]% (< [y]%).
Capacity ends at about [N] RPS, where [resource] saturates.
Risk: [one sentence].
Decision needed / conditions: [actions, owners, date].
## 2. Test configuration
| Item | Value |
|---|---|
| Build / version | [ ] |
| Environment | [size, instance types, differences from prod] |
| Data | [dataset, size, source] |
| Workload model | [open/closed], mix: [endpoint %] |
| Load profile | [steps / ramp / duration], warmup excluded: [ ] |
| Thresholds | [p95, p99, error rate] |
| Run window | [start-end, timezone] |
| Deviations from plan | [ ] |
## 3. Results vs thresholds (steady state, warmup excluded)
| Step | Achieved RPS | p50 | p95 (< [ ]) | p99 (< [ ]) | Errors (< [ ]) | Result |
|---|---|---|---|---|---|---|
| [ ] | [ ] | [ ] | [ ] | [ ] | [ ] | [PASS/FAIL] |
Summary metric (optional): Apdex [score] [T = ...]
## 4. Charts
1. RPS target vs achieved - [what to notice]
2. p50/p95/p99 over time with thresholds - [what to notice]
3. Error rate by status code - [what to notice]
4. Saturated resource: [name] - [what to notice]
5. Comparison with baseline run [id] - [what to notice]
## 5. Bottlenecks found
### B1: [name]
- Symptom: [ ]
- Evidence: [metric, value, time]
- Cause: [confirmed | hypothesis] [ ]
- Impact: [capacity ceiling / error onset in RPS]
## 6. Recommendations
| # | Action | Priority | Owner | Expected effect | Verify by |
|---|---|---|---|---|---|
| R1 | [ ] | [ ] | [ ] | [ ] | [ ] |
Re-test date: [YYYY-MM-DD]
## 7. Appendix
- Raw results / exports: [links]
- Per-endpoint percentile tables: [ ]
- Test script / scenario: [link, tool version]
- Infra config at test time: [ ]
- Dashboards (time window pinned): [links]
- Load generator health: [ ]
- Known limitations: [ ]
Before you send the report
- The verdict is one of PASS, FAIL or PASS WITH CONDITIONS, and names the load it applies to.
- Every number has a unit, and every percentile comes from a steady-state window with warmup excluded.
- Achieved RPS is shown next to target RPS at every step.
- Each bottleneck has evidence with a metric and a timestamp; hypotheses are labeled as such.
- Every recommendation has an owner, a priority and a way to verify it, and there is a re-test date.
- Deviations from the plan and discarded runs are listed.
- Links to raw results work for the people who will read the report.
- If this is a release gate, the result is attached to the release ticket and the baseline for the next regression comparison is updated.
FAQ
What should a load test report include?
A verdict with the load it applies to, the test configuration, a table of results against each threshold per load step, a few charts that prove those results, the bottlenecks found with evidence, recommendations with owners, and an appendix with raw data and run links.
What is the difference between a load test plan and a load test report?
The plan is written before the test and defines scope, workload model, thresholds and environment. The report is written after and records what actually ran, whether it passed, what limited capacity and what to do next. The report should link the plan instead of repeating it.
How long should a load test report be?
The decision part, meaning summary, configuration and results table, should fit on one or two pages. Bottlenecks and recommendations add a page or so. Everything else, such as per-endpoint tables and scripts, belongs in the appendix where it does not slow down the reader.
Which charts belong in a load test report?
Target versus achieved RPS, p50/p95/p99 latency over time with threshold lines, error rate by status code, the saturated resource on the same time axis, and a comparison with the baseline run if there is one. Each chart needs a one-line caption saying what to notice.
How do I write the verdict when some thresholds failed?
Use a fixed vocabulary: PASS, FAIL or PASS WITH CONDITIONS, always with the load level it applies to. If the target load passed but higher steps failed, say where capacity ends and which specific actions, owners and re-test date are the conditions.