Setting Latency Pass/Fail Criteria with k6 Thresholds
Learn how to use k6 thresholds to turn HTTP latency measurements into clear pass/fail signals for your load tests and CI pipelines.
07 Jan 2026, 23:39 UTC

Problem: You need a clear, automated way to decide if a load test meets latency expectations
When running a load test, it’s easy to collect lots of numbers but harder to turn them into a go/no‑go signal for your CI pipeline. Without a pass/fail rule, you have to stare at charts or parse logs manually, which slows down releases and lets regressions slip through.
Thesis: k6 thresholds let you declare numeric limits on built‑in metrics (like average request duration) and automatically mark a test run as passed or failed based on those limits
Defining a threshold in the options object
Thresholds are plain JavaScript expressions that k6 evaluates after the test finishes. You attach them to the options object using the metric name, a comparison operator, and a target value. The most common latency metric is http_req_duration, which records the time for each HTTP request.
import http from 'k6/http';
export const options = {
thresholds: {
// fail if the average request duration is >= 200 ms
http_req_duration: ['avg < 200'],
},
};
export default function () {
http.get('https://httpbin.org/delay/1');
}
Place this script in a file, e.g., latency-test.js, and run it with k6 run latency-test.js. The command needs only read access to the file and network access to the target endpoint; no special privileges are required.
Using multiple thresholds on the same metric
You can enforce several latency requirements at once by adding more strings to the array. Each string is evaluated independently, and the test fails if any of them fail.
export const options = {
thresholds: {
http_req_duration: [
'avg < 200', // average latency
'p(95) < 500', // 95th percentile
'max < 1000', // worst‑case request
],
},
};
This gives you a layered safety net: the average must be fast, most requests must stay under half a second, and no single request may exceed one second.
Worked example: verifying a threshold passes and fails
- Set a permissive threshold – average latency under 1.5 s.
- Run the test:
k6 run latency-test.js. If the average latency observed againsthttps://httpbin.org/delay/1is below 1.5 s, k6 prints a threshold summary withOKand exits with code0. - Make the threshold impossible – change it to
avg < 10(10 ms). - Run again:
k6 run latency-test.js. The summary will show a threshold violation, the overall result will be markedFAILED, and the process will exit with a non‑zero code (typically1). - Optional JSON output – add
--out json=result.jsonto the command. The generated file contains athresholdssection where each rule has anokboolean (truefor pass,falsefor fail). You can inspect this file programmatically in a CI step.
export const options = {
thresholds: {
http_req_duration: ['avg < 1500'],
},
};
export const options = {
thresholds: {
http_req_duration: ['avg < 10'],
},
};
Where to run the commands and what to check
- Local development machine or a CI agent that has k6 installed (>= v0.45).
- Ensure outbound HTTP(S) to the target endpoint is allowed (firewall/proxy).
- After each run, examine the terminal output for the line starting with
thresholdsand verify the exit code withecho $?on Unix or%ERRORLEVEL%on Windows. - Risk: setting thresholds too tight will cause false failures even when the system is acceptable; setting them too loose lets regressions pass. Start with values derived from production SLAs or baseline measurements, then adjust iteratively.
Trade‑offs and limitations
Thresholds are evaluated **after** the virtual users finish, so they do not influence the load pattern during the test. If you need to abort early when latency spikes, you must implement custom logic with the check API or use the execution option gracefulStop. Additionally, thresholds only work with numeric metrics that k6 automatically collects; custom metrics must be numbers and added via the metrics API, otherwise the threshold is silently ignored and the test may appear to pass.
Because threshold values are absolute, they do not scale with the number of virtual users or test duration. A threshold that makes sense for a 5‑minute smoke test may be too strict for a 2‑hour soak test. Always contextualize the numbers to the specific load profile you are simulating.
Actionable closing
- Identify the latency metric that matters most for your service (usually
http_req_duration). - Write a threshold expression that reflects your SLO (e.g.,
p(95) < 300). - Add the expression to the
options.thresholdsblock in your k6 script. - Run the script locally to confirm the exit code behaves as expected.
- Integrate the
k6 runcommand into your CI pipeline and treat a non‑zero exit code as a build failure. - Monitor the threshold results over time; adjust values only after reviewing baseline data or SLO changes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.