Performance testing is not just about checking whether your system works – it’s about understanding its true limits. Breakpoint testing (also known as capacity testing) helps you identify the exact point where your system starts to fail or performance becomes unacceptable. In this post, we’ll explore how to use k6 to find your system’s breakpoint.
What is Breakpoint Testing?
Breakpoint testing is the process of gradually increasing load on a system until it begins to fail or no longer meets defined performance standards. The goal is to find:
- Maximum number of users the system can handle
- Maximum throughput (requests per second)
- Point where errors or timeouts begin appearing
- Which resource becomes the bottleneck first (CPU, memory, database, etc.)
Why Find the Breakpoint?
Understanding your system’s breakpoint helps you:
- Plan capacity for infrastructure
- Set up auto-scaling appropriately
- Predict costs as traffic grows
- Prevent outages before production encounters issues
Why k6 is a Good Tool for Breakpoint Testing
- Flexible load scaling: Allows gradual increase of virtual users (VUs) with precise control over ramp-up rates
- Real-time monitoring: Provides detailed metrics including response time, throughput, and error rate during test execution
- JavaScript-based scripting: Easy to customize test scenarios and implement complex logic
- Automatic thresholds: Set up stop conditions that automatically halt tests when performance degrades beyond acceptable levels
- Versatile deployment: Runs both locally and in the cloud for different scale requirements
- Large-scale simulation: Capable of generating significant load to accurately identify system breaking points
How to Find Breakpoints With k6
Step 1: Set Up a Basic Test Script
First, create a test script with a gradual load increase configuration:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp up from 0 to 100 users in 2 minutes
{ duration: '5m', target: 100 }, // Stay at 100 users for 5 minutes
{ duration: '2m', target: 200 }, // Ramp up to 200 users
{ duration: '5m', target: 200 }, // Stay at 200 users
{ duration: '2m', target: 300 }, // Ramp up to 300 users
{ duration: '5m', target: 300 }, // Stay at 300 users
{ duration: '2m', target: 400 }, // Ramp up to 400 users
{ duration: '5m', target: 400 }, // Stay at 400 users
{ duration: '5m', target: 0 }, // Ramp down to 0
],
thresholds: {
http_req_duration: ['p(95)<500', 'p(99)<1000'],
http_req_failed: ['rate<0.01'], // Error rate < 1%
},
};
export default function () {
const res = http.get('<https://your-api.com/endpoint>');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Step 2: Gradually Increase and Observe
Effective strategies for finding breakpoints:
Method 1: Gradual Ramp-up (Recommended)
- Increase load in small increments (50-100 users per step)
- Hold steady at each level for 3-5 minutes to let the system settle
- Observe metrics to detect signs of degradation
Method 2: Binary Search
- If the system passes at 100 users and fails at 1000 users
- Test with 500 users → adjust range
- Continue narrowing the range until you find the precise breakpoint
Step 3: Set Thresholds to Detect Breakpoint
k6 allows you to define acceptable thresholds:
export const options = {
thresholds: {
// 95% of requests must be < 500ms
'http_req_duration': ['p(95)<500'],
// 99% of requests must be < 1000ms
'http_req_duration': ['p(99)<1000'],
// Error rate < 1%
'http_req_failed': ['rate<0.01'],
// Minimum throughput
'http_reqs': ['rate>100'],
},
};
When one of these thresholds is violated, that’s a sign you’re approaching the breakpoint.
Step 4: Use Custom Metrics
For deeper insights into the breakpoint, track custom metrics:
import { Trend } from 'k6/metrics';
const waitingTime = new Trend('waiting_time');
export default function () {
const res = http.get('<https://your-api.com/endpoint>');
// Track custom metric
waitingTime.add(res.timings.waiting);
check(res, {
'status is 200': (r) => r.status === 200,
});
}
Step 5: Analyze Results
Run the test and observe the following indicators:
Response Time Degradation
✓ http_req_duration......: avg=150ms p(95)=300ms ← Good at 100 users
✓ http_req_duration......: avg=450ms p(95)=800ms ← Acceptable at 200 users
✗ http_req_duration......: avg=1200ms p(95)=2500ms ← Breakpoint at ~250 users
Error Rate Increase
✓ http_req_failed........: 0.1% ← Good
✓ http_req_failed........: 0.5% ← Warning
✗ http_req_failed........: 5.2% ← Breakpoint reached
Step 6: Automated Breakpoint Detection Script
To automate breakpoint discovery, you can write a script that increases load until thresholds fail:
export const options = {
scenarios: {
breakpoint: {
executor: 'ramping-arrival-rate',
startRate: 10,
timeUnit: '1s',
preAllocatedVUs: 500,
maxVUs: 1000,
stages: [
{ target: 50, duration: '2m' },
{ target: 100, duration: '2m' },
{ target: 200, duration: '2m' },
{ target: 500, duration: '2m' },
{ target: 1000, duration: '2m' },
],
},
},
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500'],
},
};
Common Mistakes When Finding Breakpoints
- Ramping up too quickly: Increasing load too fast causes you to miss the critical transition point where performance begins to degrade
- Single metric focus: Relying only on error rate while ignoring response time, resource utilization, or other key indicators
- Skipping warm-up periods: Starting load tests without allowing the system to stabilize leads to inaccurate baseline measurements
- Insufficient monitoring: Not tracking all system components (CPU, memory, database, network) to identify the actual bottleneck
- Poor documentation: Failing to record infrastructure details, test conditions, and configuration settings makes results impossible to reproduce
- Ignoring gradual degradation: Only looking for complete failures instead of noting when performance starts declining
Best Practices
1. Test in Production-Like Environment
Breakpoints in staging can differ significantly from production if infrastructure varies.
2. Monitor Backend Resources
Use monitoring tools (Grafana, Prometheus) to observe CPU, memory, and database connections during tests.
3. Test With Realistic Scenarios
Don’t just test a simple endpoint – simulate real user journeys.
4. Warm-up Before Ramping Load
stages: [
{ duration: '5m', target: 50 }, // Warm-up
{ duration: '10m', target: 50 }, // Stabilize
// Then start ramping
]
5. Document Findings
Record:
- Breakpoint at how many users/RPS
- Which bottleneck caused it (CPU, DB, Network)
- Types of errors that appeared
- Resource utilization at breakpoint
Conclusion
Finding the breakpoint is a critical part of your performance testing strategy. With k6, you can easily set up gradual load tests to identify your system’s limits. Remember:
- Ramp up gradually for accurate results
- Set clear thresholds to detect breakpoints
- Monitor both application and infrastructure metrics
- Document findings so your team can use them for capacity planning
By understanding your system’s breakpoint, you can make informed decisions about infrastructure, auto-scaling, and ensure your system is ready for peak traffic.