Section 3 · Establishing a baseline

How to find and interpret the metrics that matter in k6 terminal output

Estimated time: 3 min

What “good” looks like in the summary

  • Thresholds section shows your gate first; every line should be green before you trust CI with the script.
  • p95 on http_req_duration is stable across two runs at the same profile (small drift is normal; wild swings mean the profile or environment is not ready).
  • http_req_failed stays at zero or inside your agreed budget; mystery 4xx or 5xx under steady load deserve a check or environment fix before you tighten thresholds.
  • Checks reflect a real success condition, not only “HTTP 200.”

Sample k6 terminal output

The block below matches the k6 v1 end-of-test summary layout (thresholds first, then grouped totals). Layout and labels can change between versions; for section order, --summary-mode, and other options, refer to End-of-test summary in the k6 documentation.

text
  █ THRESHOLDS

    http_req_duration
    ✓ 'p(95)<1500' p(95)=148.21ms
    ✓ 'p(90)<2000' p(90)=146.88ms

    http_req_failed
    ✓ 'rate<0.01' rate=0.00%


  █ TOTAL RESULTS

    checks_total.......................: 90      13.122179/s
    checks_succeeded...................: 100.00% 90 out of 90
    checks_failed......................: 0.00%   0 out of 90

    ✓ status is 200
    ✓ body is not empty

    CUSTOM
    custom_waiting_time................: avg=152.355556 min=120      med=141      max=684      p(90)=147.2    p(95)=148.8

    HTTP
    http_req_duration..................: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
      { expected_response:true }.......: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
    http_req_failed....................: 0.00%  0 out of 45
    http_reqs..........................: 45     6.56109/s

    EXECUTION
    iteration_duration.................: avg=152.38ms   min=119.37ms med=141.27ms max=684.62ms p(90)=147.11ms p(95)=148.39ms
    iterations.........................: 45     6.56109/s
    vus................................: 1      min=1       max=1
    vus_max............................: 1      min=1       max=1

    NETWORK
    data_received......................: 519 kB 76 kB/s
    data_sent..........................: 4.9 kB 718 B/s

Where to look

Values in the Example column are taken from the sample summary above so the table stays internally consistent.

What you needWhere to find itExample from sample
Latency (p95)http_req_durationp(95)148.21 ms
Throughputhttp_reqs → numeric rate before /s on that line (here 6.56109/s)6.56109/s
Error ratehttp_req_failed → percentage0.00%
Check pass ratechecks_succeeded / checks_total (summary layout varies by version)100.00% (90 of 90)
VU countvus1

Reading threshold results

When thresholds are set, each one shows a verdict:

text
  █ THRESHOLDS

    http_req_duration
    ✓ 'p(95)<1500' p(95)=148.21ms
    ✓ 'p(90)<2000' p(90)=146.88ms

    http_req_failed
    ✓ 'rate<0.01' rate=0.00%

(check mark) means the threshold passed. (X) means the threshold was breached (exit code 99).

What the numbers mean together

Read one run through three lenses. You almost never trust a single number alone.

LensAsk
Latency (p95)Are responses getting slower over time?
ThroughputDoes request rate keep up with how many VUs you added?
CorrectnessAre HTTP failures or check failures climbing?

Four common stories (heuristics for HTTP tests at steady VUs, not guarantees):

If you see…Often means…
p95 steady and low, throughput matches your ramp, errors near zeroThe system looks healthy at this load.
p95 climbs while VUs stay flat and throughput stalls or fallsWork is backing up (responses slower, queueing, or saturation).
Errors or failed checks rise while p95 stays lowAnswers are wrong or rejected even when they arrive fast. Reread checks and response bodies.
Throughput drops with the same VU countEach request is costing more time somewhere (network, app, or dependencies). Pair with http_req_duration trends.