Enforcing Performance SLAs with k6 Thresholds in CI
k6 thresholds turn load test metrics into automated pass/fail criteria, and when integrated into CI they become a reliable gate for performance SLAs.
24 Feb 2026, 06:37 UTC

You run a k6 load test and it finishes with a green summary. Yet your users are complaining about slow page loads. Without explicit thresholds, k6 reports averages and medians that can mask regressions, and the test exits with exit code 0 even when latency creeps past your service-level agreement.
Declaring thresholds as code
k6 lets you attach threshold expressions directly in your script or in a separate k6.json config file. A threshold is a boolean assertion against a collected metric. When the assertion is false for the aggregated test run, k6 exits with a non-zero code, which CI systems interpret as a build failure.
For example, this threshold checks that the 95th percentile of request durations stays under 500 ms:
thresholds: { 'http_req_duration': ['p(95) < 500'] }Worked example: a concrete threshold configuration
Imagine you’re testing a checkout endpoint that must stay fast for the majority of users. A minimal k6 script typically defines virtual users, a target URL, and checks for successful responses. The script sets the number of virtual users and test duration, then iterates over requests, collecting latency and error data. After the test runs, k6 aggregates the results and reports them in a summary.
Add a threshold block right after the script body to enforce performance limits:
thresholds: { 'http_req_duration': ['p(95) < 500'], 'http_req_failed': ['rate < 0.01'] }The first line enforces that 95 percent of requests finish under 500 ms. The second keeps the error-rate below 1 percent. Both are evaluated after the test finishes. If either condition is not met, k6 returns exit code 1.
Checking the result after a run
After running the script with k6 run script.js, k6 produces a summary JSON file when you pass the --summary-export flag:
k6 run --summary-export=report.json script.jsInspect the exported file for the http_req_duration series. You’ll find entries such as p(95) and p(99) with their computed values. Compare those numbers against the thresholds you defined; if the 95th percentile is 520 ms, the threshold p(95) < 500 fails and k6 exits non-zero.
Required permissions: standard user rights are enough on most systems. The command runs locally or in a CI container as long as the k6 binary is on the PATH. A meaningful placeholder for the target URL appears in the script as 'https://api.example.com/orders'; replace it with your actual endpoint. Risk: if the threshold is too aggressive for your environment, every test run will fail the build, so tune the percentile after observing a baseline run.
Trade-offs and limitations
- End-of-run evaluation only: thresholds are checked after all virtual users finish. A transient spike that self-corrects before the test ends will not trigger an early alert.
- Aggregation bias: a single outlier can shift the percentile enough to fail the threshold, even when most users experience acceptable latency.
- Custom metrics not auto-enforced: if you define your own metrics via
checkorcounter, those do not participate in the built-in threshold system unless you explicitly add them.
Practical verification: run the test once without thresholds to capture baseline percentiles, then adjust the p() values to reflect realistic targets. Re-run with the final thresholds and confirm the exit code matches your expectations.
Closing the performance gate
Integrate the k6 script into your CI pipeline (GitHub Actions, GitLab CI, Jenkins, etc.) by invoking k6 run --summary-export=report.json script.js and configuring the job to fail when the process exits non-zero. Pair this with a post-run step that publishes the JSON report as an artifact so developers can inspect the exact percentiles that triggered the failure. Over time, iterate on the threshold values using the collected reports, and you’ll have a self-reinforcing loop that keeps performance SLAs in check without slowing down delivery.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.