Defining Performance SLAs with k6 Thresholds
Learn how to use k6 Thresholds to define automated pass/fail criteria for your performance tests, ensuring your SLAs are met before code reaches production.
26 Feb 2026, 11:47 UTC

Automating Pass/Fail Criteria in Performance Tests
Performance testing is only useful if it provides a binary answer: did the system meet the required Service Level Agreement (SLA), or did it fail? Without automated criteria, engineers must manually inspect graphs or logs after every run to determine if a regression occurred.
k6 Thresholds solve this by allowing you to define declarative pass/fail criteria directly in your test script. When a threshold is breached, k6 marks the test as failed and returns a non-zero exit code, which allows CI/CD pipelines (like GitHub Actions or GitLab CI) to automatically stop a deployment if performance degrades.
How Thresholds Work
Thresholds are defined within the options object of a k6 script. You target a specific metric—either a built-in one like http_req_duration or a custom Trend metric—and apply a logical operator to define the acceptable limit.
The most common operators include:
- Percentiles (p): Ensures a specific percentage of requests stay below a value (e.g.,
p(95)for the 95th percentile). - Averages (avg): The mean value of the metric.
- Rates (rate): The ratio of occurrences, typically used for error rates (e.g.,
rate < 0.01for less than 1% failure).
Implementation Example
The following configuration sets a strict SLA for response times and a low tolerance for HTTP errors. Run this script using the k6 run command from your terminal.
import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
vus: 10,
duration: '30s',
thresholds: {
// 95% of requests must complete below 200ms
http_req_duration: ['p(95)<200'],
// The error rate must be less than 1%
http_req_failed: ['rate<0.01'],
// Custom metric: 99% of check-out requests must be under 500ms
'http_req_duration{name:checkout}': ['p(99)<500'],
},
};
export default function () {
// Tagging the request allows for the scoped threshold above
http.get('https://test.k6.io', { tags: { name: 'checkout' } });
sleep(1);
}
Scoped Thresholds
In complex tests, a single global threshold is often insufficient. For example, a login endpoint may be slower than a health-check endpoint. You can scope thresholds by adding tags to your requests (as shown in the {name:checkout} example above). This allows you to maintain different performance expectations for different user personas or API endpoints within the same test run.
Verification and CI/CD Integration
To verify that your thresholds are working, you can intentionally set an impossible limit, such as p(95)<1. When the test completes, k6 will print a summary to the console explicitly marking the threshold as failed.
To check the exit code in a Unix-based shell (Linux or macOS), run the following command immediately after the test finishes:
echo $?
A result of 0 indicates success; any non-zero value indicates a threshold breach. This is the mechanism CI tools use to trigger a build failure.
Limitations and Common Pitfalls
Silent Failures via Typos
k6 does not throw an error if you misspell a metric name in the thresholds object. If you write http_req_duraton instead of http_req_duration, k6 will simply ignore the threshold because it never finds a matching metric. Always verify the "Thresholds" section of the final summary output to ensure your criteria were actually evaluated.
Sample Size Volatility
Using extremely high percentiles (e.g., p(99.9)) on short tests or with very few Virtual Users (VUs) can lead to "flaky" tests. In small sample sizes, a single outlier (like a cold-start or a network hiccup) can spike the p99.9 and fail a build, even if the system is generally healthy. For stable CI pipelines, prefer p(95) or p(99) unless you have a high volume of requests.
State Rollback
Since thresholds are declarative configurations within the script and do not modify the target system's state or the k6 installation, no rollback is required. To revert a threshold change, simply modify the options object in your source code.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.