Load Test Report Template
A standardized template for documenting load test results and recommendations.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
Load test reports communicate performance findings to stakeholders and track improvements over time. Without a standard format, teams waste time re-explaining metrics and context. This template provides a consistent structure for documenting benchmarks, bottlenecks, and recommendations.
When to Use
- For alternatives, see Test Coverage Report Template.
Use this resource when:
- Reporting results after a scheduled load test cycle
- Sharing performance findings with product managers or executives
- Creating a baseline before a major release or infrastructure change
Solution
# Load Test Report
## 1. Executive Summary
| Field | Value |
|-------|-------|
| Application / Service | `name` |
| Test Date | `YYYY-MM-DD` |
| Environment | `staging / production-like` |
| Tool Used | `k6 / JMeter / Gatling / Locust` |
| Tester | `name` |
| Overall Result | `PASS / PASS with warnings / FAIL` |
- **Goal**: Briefly state what was tested and why.
- **Key Finding**: One-line summary of the most important result.
## 2. Test Scope
- **Endpoints tested**: List URLs or user flows
- **Load profile**: Concurrent users, ramp-up, duration, steady state
- **Data used**: Realistic datasets, anonymized production data, or synthetic
## 3. Results
### Throughput
| Metric | Target | Actual | Status |
|--------|--------|--------|--------|
| Requests/sec | 1,000 | 1,150 | PASS |
| Transactions/sec | 500 | 480 | PASS |
### Latency (ms)
| Percentile | Target | Actual | Status |
|------------|--------|--------|--------|
| p50 | < 100 | 85 | PASS |
| p95 | < 300 | 320 | WARNING |
| p99 | < 500 | 680 | FAIL |
### Error Rate
| Metric | Target | Actual | Status |
|--------|--------|--------|--------|
| HTTP 5xx | < 0.1% | 0.05% | PASS |
| Timeout | < 0.01% | 0.00% | PASS |
### Resource Utilization
| Resource | Target | Peak | Status |
|----------|--------|------|--------|
| CPU | < 70% | 65% | PASS |
| Memory | < 80% | 82% | WARNING |
| DB Connections | < 80% | 78% | PASS |
## 4. Bottlenecks Identified
1. **Bottleneck**: Database query X takes 400ms under load
- **Impact**: p99 latency exceeds target
- **Evidence**: Query plan screenshot, APM trace link
- **Recommendation**: Add composite index on `(user_id, created_at)`
2. **Bottleneck**: Connection pool exhaustion at 1,200 users
- **Impact**: 503 errors spike
- **Evidence**: Pool metrics dashboard link
- **Recommendation**: Increase pool size from 20 to 40
## 5. Action Items
| Priority | Action | Owner | Due Date |
|----------|--------|-------|----------|
| P0 | Add DB index on query X | @backend-team | 2026-06-28 |
| P1 | Increase connection pool | @devops-team | 2026-06-25 |
| P2 | Evaluate caching layer | @architect | 2026-07-05 |
## 6. Appendices
- Link to test script repository
- Link to raw results / CSV exports
- Link to APM dashboards (Grafana, Datadog)
- Link to incident runbook if follow-up is needed
Explanation
The template separates summary (for executives), details (for engineers), and actions (for planning). The tabular format makes pass/fail status scannable. Bottlenecks link to evidence so reviewers can verify claims. Action items include owners and dates to prevent findings from being forgotten.
Detailed Scenario: Load Testing an E-commerce Checkout Flow
System: E-commerce checkout API
Tool: k6
Goal: Validate checkout handles 500 concurrent users at peak
Test script (k6):
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
stages: [
{ duration: "2m", target: 100 },
{ duration: "5m", target: 500 },
{ duration: "2m", target: 500 },
{ duration: "1m", target: 0 },
],
thresholds: {
http_req_duration: ["p(95)<300", "p(99)<500"],
http_req_failed: ["rate<0.01"],
},
};
export default function () {
const res = http.post("https://staging.example.com/api/checkout",
JSON.stringify({ cart_id: "cart_123", payment_method: "card" }),
{ headers: { "Content-Type": "application/json" } });
check(res, {
"status is 201": (r) => r.status === 201,
"response has order_id": (r) => r.json("order_id") !== undefined,
});
sleep(1);
}
Execution:
$ k6 run --out json=results.json checkout_load.js
Results:
- p50 latency: 85ms (target < 100ms) PASS
- p95 latency: 320ms (target < 300ms) WARNING
- p99 latency: 680ms (target < 500ms) FAIL
- Error rate: 0.05% (target < 0.1%) PASS
- Throughput: 1,150 req/s (target 1,000) PASS
Bottleneck found:
- DB query on order_items table takes 400ms under load
- Missing composite index on (order_id, product_sku)
- Connection pool exhausted at 1,200 concurrent users
Actions:
P0: Add index on order_items(order_id, product_sku) - @backend
P1: Increase pool size 20 -> 40 - @devops
P2: Add Redis cache for product lookups - @architect
What percentiles should I report?
Report p50 (median), p95, and p99 at minimum. p50 shows typical experience. p95 catches most degradation. p99 reveals tail latency problems that affect real users. If you have SLOs at p99.9, include that too. Never report only averages — they hide tail latency spikes.
How do I simulate realistic user behavior in load tests?
Use think time (pauses between actions) to match real user patterns. Distribute requests across endpoints proportionally to production traffic. Include browsing, searching, and checkout flows — not just the heaviest endpoint. Parameterize test data so each virtual user hits different records to avoid cache hits skewing results.
Variants
| Context | Approach | Notes |
|---|---|---|
| Pre-release | Baseline comparison | Include previous release numbers side-by-side |
| Incident recovery | Post-fix validation | Focus on the specific path that failed |
| Capacity planning | Saturation test | Document the breaking point and limiting resource |
What works
- Run tests in an environment that mirrors production (hardware, data size, network)
- Warm up the system before recording metrics to avoid cold-start bias
- Report percentiles (p50, p95, p99) instead of averages to capture tail latency
- Include graphs and links to dashboards, not just static numbers
- Attach the exact test script so the test is reproducible
Common Mistakes
- Testing on developer laptops or undersized environments
- Using tiny datasets that hide real-world query performance
- Reporting only average latency, which hides p99 degradation
- Omitting error rates and focusing only on throughput
- Not assigning owners to action items, so nothing gets fixed
Troubleshooting
- Flaky tests: isolate shared state, time, and randomness. Make tests independent and deterministic; quarantine persistently flaky tests.
- High coverage but bugs in production: coverage does not guarantee correctness. Add mutation testing, property-based tests, or contract tests.
- Slow test suite: parallelize, mock slow dependencies, and avoid end-to-end tests for logic that can be unit tested.
- Tests pass locally but fail in CI: check environment differences, timezone, locale, and dependency versions. Pin tool versions.
- Debugging a failing integration test: log request/response payloads and use a dedicated test database. Reset state before each test.
FAQ
How do I define targets for latency and throughput?
Targets should come from SLAs, product requirements, or historical baselines. If none exist, use the 80th percentile of current production traffic as a starting point.
Should I run load tests against production?
Avoid load testing production directly. Use a production-like environment with similar data volume and infrastructure. For read-only endpoints, consider traffic mirroring or shadow testing.
How often should load tests be repeated?
Before every major release, after major infrastructure changes, and quarterly as a regression check. Automate nightly smoke tests with small load to catch regressions early.
End of document. Review and update quarterly.
Common Production Pitfalls
- Leaving required fields blank or using vague one-word answers.
- Filling the document once and never updating it after scope or decisions change.
- Storing the document where the team does not look during incidents or reviews.
- Not assigning an owner, due date, or review cadence.
- Copying boilerplate without removing sections that do not apply.
- Skipping version control, which makes rollback and accountability impossible.
- Failing to link the document to related decisions or follow-up actions.
- Avoiding quarterly reviews that would retire stale or unused sections.
Related Resources
Load Testing APIs with k6 and Threshold-Based Assertions
How to write and run load tests with k6 to measure API performance, validate SLOs, and identify bottlenecks before production deployment
GuideCI/CD Pipeline Guide
A practical guide to building CI/CD pipelines with GitHub Actions, testing, deployment strategies, and rollback procedures.
GuideTest-Driven Development (TDD) — A Practical Workflow
Learn TDD step by step: write a failing test, make it pass, refactor. Red-Green-Refactor with real examples in Python, JavaScript, and Java.