Skip to main content

Performance Testing Quick Reference

A lookup page for planning, scripting and reading performance tests, with k6 syntax and the maths you need.

How to use this page

This page is for looking things up, not for learning from scratch. New to performance testing? Start with the performance testing cheat sheet, which explains each idea with an exercise on a practice lab. For the ordered plan, see the performance testing learning path.

Quick Navigation​

Planning: Test types · Formulas · SLO examples · Workload template

k6: CLI · Options · Executors · Thresholds · Checks and HTTP · Custom metrics · Data and lifecycle · Built-in metrics

Analysis: Bottleneck signs · Report outline · Tool equivalents


Test types​

Typek6 shapeExample
Smokevus: 1, duration: '1m'Script works
Loadramping-vus or ramping-arrival-rate up to peak, holdstages: [{ target: 50, duration: '5m' }, { target: 50, duration: '30m' }, { target: 0, duration: '2m' }]
Stressramping-arrival-rate past peakTargets 1× → 1.5× → 2× → 3× peak
SpikeSeparate scenarios with startTime5 → 150 → 5 users
SoakConstant load for hoursvus: 50, duration: '4h'
BreakpointSlow, long ramp with abortOnFailramping-arrival-rate to a very high target

Formulas​

WhatFormulaExample
Little's Lawconcurrency = arrival rate × time in system20 sessions/s × 90 s = 1,800 users
Max throughput of a poolpool size ÷ time held5 ÷ 0.05 s = 100/s
Requests per second from VUs (closed model)VUs ÷ (response time + think time)100 ÷ (0.2 + 1.8 s) = 50 req/s
Peak from daily volume (rough)daily requests ÷ 86,400 × peak factor4.32 M ÷ 86,400 × 3 = 150 req/s
Error ratefailed ÷ total12 ÷ 6,000 = 0.2%
Headroom(capacity − peak) ÷ peak(100 − 60) ÷ 60 ≈ 67%

Peak factor (peak hour vs average) is an assumption — get it from real traffic data.

SLO examples​

Checkout API:  at 200 req/s, p95 < 400 ms, p99 < 1 s, errors < 0.1%
Search: at 500 req/s, p95 < 300 ms
Login: p95 < 800 ms; 0 errors at 3× normal peak for 10 minutes
Soak: 4 h at normal peak; memory and p95 flat (± 10%) from hour 1 to hour 4

Workload template​

Peak time:        <day/hour>        Source: <analytics/logs, date range>
Peak rate: <n> req/s (or sessions/h) Growth factor to test: ×<n>
Journey mix: browse <n>% | search <n>% | checkout <n>% | account <n>%
Think time: <n>–<n> s between steps
Data: <n> users, <n> products, <n> orders (volume in test DB)
Out of scope: <third parties mocked, batch jobs>

CLI​

CommandDoes
k6 run script.jsRun a test
k6 run --vus 10 --duration 30s script.jsOverride load from the command line
k6 run -e BASE_URL=https://staging.example.com script.jsPass a variable (__ENV.BASE_URL)
k6 run --quiet script.jsNo progress bar
k6 run --out json=results.json script.jsEvery data point to a file
k6 run --summary-export=summary.json script.jsSummary to a file (or use handleSummary)
k6 inspect script.jsShow the resolved options
k6 versionVersion

Exit code 99 = a threshold failed; that's what fails CI.

Options​

export const options = {
vus: 10, duration: '30s', // simple fixed load
stages: [{ target: 20, duration: '1m' }], // or ramping VUs
scenarios: { /* see executors */ }, // or full control
thresholds: { http_req_duration: ['p(95)<300'] },
noConnectionReuse: false, // true = new connection per request
insecureSkipTLSVerify: false, // true only for test certificates
summaryTrendStats: ['avg', 'med', 'p(90)', 'p(95)', 'p(99)', 'max'],
};

Executors​

ExecutorKey optionsModel
shared-iterationsvus, iterationsFixed work, shared
per-vu-iterationsvus, iterationsFixed work per VU
constant-vusvus, durationClosed
ramping-vusstartVUs, stagesClosed
constant-arrival-raterate, timeUnit, duration, preAllocatedVUs, maxVUsOpen
ramping-arrival-ratestartRate, timeUnit, stages, preAllocatedVUs, maxVUsOpen
externally-controlledvus, maxVUsControlled at runtime

Scenario extras: exec: 'functionName', startTime: '30s', tags: {…}, env: {…}.

dropped_iterations > 0 on an arrival-rate executor = not enough VUs to keep the rate (raise maxVUs) — or the system is so slow that VUs are all busy.

Thresholds​

thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<1000'], // several rules
'http_req_duration{name:search}': ['p(95)<300'], // one tagged endpoint
'http_req_duration{scenario:after}': ['p(95)<50'], // one scenario
http_req_failed: ['rate<0.01'],
checks: ['rate>0.99'],
order_time: [{ threshold: 'p(95)<500', abortOnFail: true, delayAbortEval: '10s' }],
}

Aggregations: Trend avg, min, max, med, p(N); Rate rate; Counter count, rate; Gauge value.

Checks and HTTP​

import http from 'k6/http';
import { check, group, sleep } from 'k6';

const res = http.post(url, JSON.stringify(body), {
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
tags: { name: 'create-order' },
timeout: '10s',
});
check(res, {
'status 201': (r) => r.status === 201,
'has id': (r) => r.json('orderId') !== undefined,
'under 500 ms': (r) => r.timings.duration < 500,
});
group('checkout', () => { /* several requests reported as one group */ });
sleep(Math.random() * 2 + 1); // 1–3 s think time
http.batch([['GET', url1], ['GET', url2]]); // parallel requests, like a browser

r.timings: blocked, connecting, tls_handshaking, sending, waiting (time to first byte), receiving, duration.

Custom metrics​

import { Trend, Counter, Rate, Gauge } from 'k6/metrics';
const t = new Trend('order_time', true); t.add(res.timings.duration);
const c = new Counter('orders'); c.add(1);
const r = new Rate('sold_out'); r.add(res.status === 409);
const g = new Gauge('queue_depth'); g.add(res.json('poolWaiting'));

Data and lifecycle​

import { SharedArray } from 'k6/data';
import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';
const users = new SharedArray('users', () => papaparse.parse(open('./users.csv'), { header: true }).data);

export function setup() { return { token: login() }; } // once, before load
export default function (data) { /* uses data.token */ } // every iteration
export function teardown(data) { /* once, after load */ }
export function handleSummary(data) { return { 'summary.json': JSON.stringify(data) }; }

__VU (1-based VU number) and __ITER (0-based iteration) help pick unique data: users[(__VU - 1) % users.length].

Built-in metrics​

MetricTypeMeaning
http_reqsCounterRequests sent
http_req_durationTrendSending + waiting + receiving
http_req_waitingTrendTime to first byte
http_req_failedRateFailed requests (by default status ≥ 400 or network error)
iterations / iteration_durationCounter / TrendLoops completed / time per loop
vus / vus_maxGaugeActive / allocated VUs
checksRateChecks passed
data_sent / data_receivedCounterBytes
dropped_iterationsCounterIterations an arrival-rate executor couldn't start

Bottleneck signs​

PatternLikely causeWhere to look
Throughput flat, latency rising, CPU ~100%CPU-bound codeProfiler, CPU per process
Latency jumps at one exact concurrencyPool limit (DB, threads, HTTP client)Pool metrics: in-use, waiting
One endpoint slow, others fineSlow query / missing index / N+1 queriesSlow-query log, traces
Periodic latency spikesGarbage collection, cron jobs, autoscalingGC logs, job schedules
Memory climbs and never fallsLeak (cache without limit, listeners)Heap metrics over a soak
Errors rise, latency fallsFailing fast (rate limit, circuit breaker, 5xx)Error codes, logs
Everything slow including static filesNetwork, load balancer, generator overloadedGenerator CPU, network graphs

Report outline​

1. Verdict vs SLOs; capacity estimate
2. Set-up: environment, data volume, workload model, tool, duration
3. Results: p50/p95/p99, throughput, errors per journey; graphs over time
4. Bottleneck with evidence
5. Recommendations, ranked
6. Next test and baseline for comparison

Tool equivalents​

Ideak6JMeterGatlingLocust
User flowdefault functionThread Group + samplersScenarioHttpUser task
UsersVUsThreadsUsersUsers
Arrival rate*-arrival-rate executorsThroughput timers / pluginsinjectOpen(constantUsersPerSec)constant_pacing
Think timesleep()Timerspause()wait_time
Assertioncheck()Assertionscheck()Manual response.failure()
Pass/failthresholds(plugins / CI parsing)assertionsCustom exit code

Need more detail? Cheat sheet · Best practices · Learning path · Full guide