By Performate
API Performance Testing Checklist: 12 Things Teams Forget
Twelve concrete checks before and during API load tests—environment realism, auth, data safety, metrics, and gates—grounded in k6 and release practice.
Your staging run hit 500 concurrent users and checkout stayed green—so the release shipped. Two days later production p99 doubled because the test never exercised OAuth token refresh, shared sandbox rows collided under write load, and nobody tagged requests by route. Serious API load testing is less about "how many VUs" and more about whether the question, environment, and metrics match production risk.
This checklist captures twelve checks teams forget before they scale traffic—especially when stakeholders will read the outcome. Pair it with stress vs load vs spike for the right traffic shape and k6 thresholds examples when you define pass/fail.
Why checklists fail without executable structure
Most performance postmortems trace back to the same gaps:
- Unnamed decisions: runs happen because "we should load test," not because a release gate needs a specific answer.
- Environment lies: staging without realistic data volume, cache warmth, or network path produces charts nobody should trust.
- Untagged metrics: aggregate
http_req_durationhides which endpoint regressed. - Missing abort ownership: saturation spills outside the sandbox and surprises security or platform on-call.
A checklist only helps when it maps to k6 scenarios, thresholds, and archived parameters—not slide decks. The sections below turn each item into something you can verify in script and summary output.
Practical k6 implementation: checklist encoded in options
The example script embeds checklist items as tags, thresholds, and setup hooks so pass/fail is objective—not a meeting opinion.
Example script (illustrative—not a production-ready test). Adapt URLs, auth, datasets, and thresholds to your environment.
What this example demonstrates:
- Decision tag:
decision:release-gate-checkoutdocuments why the run exists. - Route-scoped thresholds: checkout gets tighter SLOs than a health probe.
- Setup isolation:
setup()fetches a dedicated test tenant token instead of reusing shared credentials. - Smoke-first duration: two-minute ramp before the main stage—item 6 on the checklist.
import http from 'k6/http';
import { check, sleep } from 'k6';
const BASE = __ENV.API_BASE || 'https://staging.example.com';
const DECISION = __ENV.TEST_DECISION || 'release-gate-checkout';
export function setup() {
// Checklist #3: freeze credentials — dedicated tenant per run
const authRes = http.post(`${BASE}/oauth/token`, {
grant_type: 'client_credentials',
client_id: __ENV.CLIENT_ID,
client_secret: __ENV.CLIENT_SECRET,
scope: 'checkout:write',
});
check(authRes, { 'token issued': (r) => r.status === 200 });
return { token: authRes.json('access_token') };
}
export const options = {
tags: { decision: DECISION, env: __ENV.ENV_NAME || 'staging' },
scenarios: {
smoke_auth: {
executor: 'constant-vus',
vus: 5,
duration: '2m',
tags: { phase: 'smoke', route: 'checkout' },
exec: 'checkout',
},
load_checkout: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '3m', target: 40 },
{ duration: '10m', target: 40 },
{ duration: '2m', target: 0 },
],
tags: { phase: 'load', route: 'checkout' },
exec: 'checkout',
startTime: '2m',
},
},
thresholds: {
'http_req_duration{route:checkout}': ['p(95)<800', 'p(99)<1200'],
'http_req_failed{route:checkout}': ['rate<0.01'],
'checks{phase:smoke}': ['rate>0.99'],
},
};
export function checkout(data) {
const idempotencyKey = `load-${__VU}-${__ITER}-${Date.now()}`;
const body = JSON.stringify({ sku: 'SKU-100', qty: 1 });
const res = http.post(`${BASE}/v2/checkout`, body, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${data.token}`,
'Idempotency-Key': idempotencyKey,
},
tags: { route: 'checkout', decision: DECISION },
});
check(res, {
'checkout 2xx': (r) => r.status >= 200 && r.status < 300,
'no timeout': (r) => r.status !== 0,
});
sleep(0.5);
}
Pro tip (example command): archive parameters with the run for checklist item 11.
TEST_DECISION=release-gate-checkout ENV_NAME=staging-v4 k6 run checkout-checklist.js --summary-export=run-evidence.json
The 12 checks: decision table
| # | Check | Pass signal | Common miss |
|---|---|---|---|
| 1 | Name the decision the run supports | One-sentence gate documented in tags or README | "See how it handles load" |
| 2 | Match environment fidelity to the question | Missing fidelity listed in run notes | Treating staging charts as prod forecasts |
| 3 | Freeze URLs, tenants, credentials | Env vars recorded; no mystery sandboxes | Rotating keys mid-run |
| 4 | Isolate or reset test data | Idempotency keys or dedicated prefixes | Shared rows → flaky "regressions" |
| 5 | Tag requests for post-run diagnosis | Per-route http_req_duration in summary | One aggregate latency line |
| 6 | Smoke before marathon | Short scenario passes checks first | Debugging script bugs at scale |
| 7 | Tie thresholds to product risk | Tighter SLO on checkout vs admin | Vanity hero numbers |
| 8 | Separate functional from load proof | Contract tests in CI; load answers concurrency | Green functional = ship |
| 9 | Watch errors by type | Timeouts vs 5xx vs business soft-fails split | Single http_req_failed blob |
| 10 | Correlate server-side when allowed | APM window matches test duration | Optimizing scripts not systems |
| 11 | Capture scenario params with report | VU model, duration, git SHA archived | Chart with no context |
| 12 | Assign abort owner | Named contact + comms path to on-call | Surprise saturation |
Use strict thresholds on revenue paths (items 7–9). Use lighter gates on internal admin unless the decision explicitly covers those routes.
Use smoke-first staging (items 5–6) before any marathon soak or stress campaign (common mistakes).
Use correlation (item 10) with API bottleneck analysis when APM exists for the same window.
Pre-run checklist (copy before you scale)
Before you start the main scenario:
- Decision sentence written: "After this test we will approve/reject ______ because we measured ______."
- Environment gaps documented (data volume, cache warmth, network path).
- Base URL, OAuth flow, and tenant per VU recorded in env file—not chat.
- Test data isolation plan confirmed with platform (prefixes, resets, idempotency).
- Tags defined for every route under test (
route:checkout, etc.). - Smoke scenario scheduled with strict check thresholds.
- k6 thresholds encode product risk, not best-day weekend numbers.
- Abort owner named with authority to stop run and notify on-call.
- Server-side dashboards open for the same time window (if policy allows).
- Export path chosen for summary JSON + git/build identifiers.
Google's SRE material frames aligned incentives between SLIs and real user pain—your environment contract and checklist should reflect that (alerting on SLOs).
How Performate helps you execute this checklist
Boilerplate kills compliance with items 1–12. Below is a concrete workflow example for the checkout release gate this article discusses.
Example: run the checklist on a Postman collection without losing tags or evidence
- Import the collection that product already trusts for functional tests. Problem solved: checklist item 3—URLs and auth shapes stay aligned with daily QA.
- Add tags per request in the scenario panel:
route:checkout,decision:release-gate-checkout. Problem solved: item 5—summaries slice latency by endpoint automatically. - Configure smoke then load as two scenarios—2 minutes at 5 VUs, then ramp to 40. Problem solved: item 6 without hand-editing executor blocks.
- Set thresholds in the UI matching negotiated SLO (
p95, error rate). Problem solved: item 7—objective pass/fail visible before export. - Run and open the integrated report; split errors by type (timeouts vs 5xx). Problem solved: items 9 and 11 in one view.
- Export k6 script + summary for CI and attach git SHA from your release branch. Problem solved: evidence survives the meeting; reruns compare apples to apples.
Starting from Postman? Follow Postman to k6 step-by-step first so imports do not skip critical variables.
That workflow maps to the cta in this post: execute the checklist with repeatable scenarios, reports, and exports in one desktop workflow.
Closing takeaway
A load test without a decision, tags, and archived parameters is a demo—not evidence. Walk the twelve checks before you scale; encode the important ones in k6 options so pass/fail survives the release meeting.
Run smoke on your next candidate build this week—and confirm checkout tags, thresholds, and abort owner are named before anyone asks for "just five more minutes at 2× traffic."
Try Performate free | Book a demo | k6 scenarios documentation
Ready to optimize your API performance?
Download Performate to execute this checklist with repeatable scenarios, reports, and exports.