Thresholds are pass/fail criteria for your load tests. They specify the acceptable limits for your metrics, allowing you to automate test evaluation.
What are Thresholds?
From metrics/thresholds.go, thresholds are expressions that evaluate metric values against defined criteria. If a threshold fails, k6 exits with a non-zero status code.
import http from 'k6/http';
export const options = {
thresholds: {
// 95th percentile response time must be below 500ms
http_req_duration: ['p(95)<500'],
// Less than 1% of requests can fail
http_req_failed: ['rate<0.01'],
},
};
export default function() {
http.get('https://quickpizza.grafana.com/');
}
When thresholds fail, k6 exits with code 99 (from errext/exitcodes).
Threshold Syntax
From metrics/thresholds_parser.go, threshold expressions follow this format:
aggregationMethod(value) operator value
Supported Operators
From metrics/thresholds.go, the run() function supports:
> - Greater than
>= - Greater than or equal
< - Less than
<= - Less than or equal
== or === - Equal to
!= - Not equal to
Examples
export const options = {
thresholds: {
http_req_duration: ['p(95)<500'], // 95th percentile < 500ms
http_req_duration: ['avg<200'], // Average < 200ms
http_req_duration: ['max<2000'], // Maximum < 2s
http_req_duration: ['med<150'], // Median < 150ms
http_req_failed: ['rate<0.01'], // Error rate < 1%
http_reqs: ['count>100'], // At least 100 requests
checks: ['rate>0.95'], // 95% of checks pass
},
};
Aggregation Methods by Metric Type
From metrics/metric_type.go, each metric type supports specific aggregation methods:
Counter Metrics
Supported methods: count, rate
export const options = {
thresholds: {
http_reqs: ['count>1000'], // Total requests > 1000
http_reqs: ['rate>50'], // Request rate > 50/sec
iterations: ['count>=500'], // At least 500 iterations
},
};
Gauge Metrics
Supported methods: value
export const options = {
thresholds: {
vus: ['value>10'], // VUs > 10
vus_max: ['value<=100'], // Max VUs ≤ 100
},
};
Trend Metrics
Supported methods: avg, min, max, med, p(N)
export const options = {
thresholds: {
http_req_duration: [
'avg<200', // Average < 200ms
'min<50', // Minimum < 50ms
'max<1000', // Maximum < 1s
'med<150', // Median < 150ms
'p(90)<400', // 90th percentile < 400ms
'p(95)<500', // 95th percentile < 500ms
'p(99)<800', // 99th percentile < 800ms
'p(99.9)<1000', // 99.9th percentile < 1s
],
iteration_duration: ['p(95)<5000'], // 95% complete in 5s
},
};
Rate Metrics
Supported methods: rate
export const options = {
thresholds: {
checks: ['rate>0.95'], // 95% success rate
http_req_failed: ['rate<0.01'], // < 1% failures
},
};
Multiple Thresholds
Define multiple thresholds for the same metric from examples/thresholds.js:
export const options = {
thresholds: {
http_req_duration: [
'p(95)<500', // First threshold
'p(99)<1000', // Second threshold
'max<2000', // Third threshold
],
},
};
All thresholds must pass for the test to succeed.
Thresholds on Tagged Metrics
From examples/thresholds.js, filter metrics by tags:
export const options = {
thresholds: {
// Threshold for all requests
'http_req_duration': ['p(95)<500'],
// Threshold for specific URL
'http_req_duration{name:http://httpbin.org/post}': ['max<1000'],
// Threshold for custom tag
'http_req_duration{staticAsset:yes}': ['p(99)<500'],
},
};
export default function() {
http.get('https://quickpizza.grafana.com/');
http.post('https://quickpizza.grafana.com/post', {data: 'some data'});
http.get('https://quickpizza.grafana.com/style.css', {
tags: { staticAsset: 'yes' },
});
}
Aborting on Threshold Failure
From metrics/thresholds.go, use abortOnFail to stop tests immediately when a threshold fails:
export const options = {
thresholds: {
http_req_failed: [
// Normal threshold
'rate<0.01',
// Abort if error rate exceeds 5%
{ threshold: 'rate<=0.05', abortOnFail: true },
],
},
};
From the source code:
- When
abortOnFail is true and the threshold fails, ts.Abort is set
- The test terminates early
- Useful for preventing wasted test time when critical issues occur
Abort Grace Period
From metrics/thresholds.go, delay abort to allow test startup:
export const options = {
thresholds: {
http_req_failed: [
{
threshold: 'rate<=0.05',
abortOnFail: true,
delayAbortEval: '1m', // Don't abort for first minute
},
],
},
};
Grace periods prevent false positives during test ramp-up when metrics may be unstable.
Real-World Example
From examples/thresholds_readme_example.js:
import http from 'k6/http';
import { check, group, sleep } from 'k6';
import { Rate } from 'k6/metrics';
// Custom metric to track failure rates
const failureRate = new Rate('check_failure_rate');
export const options = {
stages: [
{ target: 50, duration: '1m' },
{ target: 50, duration: '3m30s' },
{ target: 0, duration: '30s' },
],
thresholds: {
// 95th percentile of all requests < 750ms
'http_req_duration': ['p(95)<750'],
// Static assets finish faster
'http_req_duration{staticAsset:yes}': ['p(99)<500'],
// Custom metric thresholds
'check_failure_rate': [
// Global failure rate < 1%
'rate<0.01',
// Abort if it exceeds 5%
{ threshold: 'rate<=0.05', abortOnFail: true },
],
},
};
export default function () {
const response = http.get('https://quickpizza.grafana.com/test.k6.io/');
const checkRes = check(response, {
'http2 is used': (r) => r.proto === 'HTTP/2.0',
'status is 200': (r) => r.status === 200,
'content is present': (r) => r.body.indexOf('This is a replacement') !== -1,
});
// Track failures
failureRate.add(!checkRes);
// Load static assets
group('Static Assets', function () {
const resps = http.batch([
['GET', 'https://quickpizza.grafana.com/test.k6.io/static/css/site.css',
null, { tags: { staticAsset: 'yes' } }],
['GET', 'https://quickpizza.grafana.com/test.k6.io/static/favicon.ico',
null, { tags: { staticAsset: 'yes' } }],
]);
failureRate.add(!check(resps, {
'status is 200': (r) => r[0].status === 200 && r[1].status === 200,
}));
});
sleep(Math.random() * 3 + 2);
}
Threshold Validation
From metrics/thresholds.go, the Validate() function ensures:
- The metric exists in the registry
- The aggregation method is supported for the metric type
- The threshold expression is syntactically correct
Invalid thresholds cause k6 to exit with exitcodes.InvalidConfig.
Common Validation Errors
export const options = {
thresholds: {
// ❌ ERROR: 'avg' not supported for Counter
http_reqs: ['avg<100'],
// ❌ ERROR: 'count' not supported for Rate
checks: ['count>50'],
// ✅ CORRECT: 'rate' supported for Rate
checks: ['rate>0.95'],
// ✅ CORRECT: 'count' supported for Counter
http_reqs: ['count>100'],
},
};
Threshold Execution
From metrics/thresholds.go, the Run() method:
- Collects sink values (aggregated metrics)
- Evaluates each threshold expression
- Sets
LastFailed flag on failing thresholds
- Determines if test should abort
Sink Values
From metrics/thresholds.go, different sinks provide different values:
CounterSink:
count - Total value
rate - Value per second
GaugeSink:
TrendSink:
min, max, avg, med - Statistics
p(N) - Percentiles (calculated on demand)
RateSink:
rate - Ratio of true values to total
Thresholds in CI/CD
Thresholds make k6 tests suitable for automated pipelines:
# Run test
k6 run test.js
# Check exit code
if [ $? -eq 0 ]; then
echo "Test passed!"
else
echo "Test failed - thresholds not met"
exit 1
fi
Exit Codes
0 - All thresholds passed
99 - One or more thresholds failed (from errext/exitcodes)
- Other codes indicate different errors
Best Practices
Start Conservative
Begin with loose thresholds and tighten them as you understand system behavior.
Focus on Percentiles
Use p(95) or p(99) instead of averages to catch outliers.
Set Multiple Thresholds
Define thresholds for different aspects: latency, error rate, throughput.
Use Tags for Granularity
Apply different thresholds to different request types or endpoints.
Add Abort Conditions
Use abortOnFail for critical failures to save resources.
Too strict thresholds cause false failures. Base thresholds on realistic performance expectations.
Combine thresholds with custom metrics to track business-specific SLOs (Service Level Objectives).
Common Threshold Patterns
export const options = {
thresholds: {
http_req_duration: ['p(99)<1000', 'p(95)<500'],
http_req_failed: ['rate<0.001'], // 99.9% success
http_reqs: ['rate>10'], // Minimum throughput
},
};
Multi-Environment Thresholds
const thresholds = __ENV.ENV === 'prod'
? { http_req_duration: ['p(95)<200'] } // Strict for production
: { http_req_duration: ['p(95)<1000'] }; // Relaxed for staging
export const options = { thresholds };
Progressive Thresholds
export const options = {
thresholds: {
// Must meet all of these
http_req_duration: [
'p(50)<100', // Half of requests < 100ms
'p(90)<300', // 90% < 300ms
'p(95)<500', // 95% < 500ms
'p(99)<1000', // 99% < 1s
],
},
};
Thresholds transform k6 from a measurement tool into an automated testing framework, enabling continuous performance validation in your development pipeline.