API Load Testing with k6 — Scripting, Metrics, and Breakpoint Analysis
In this tutorial, you will learn about API Load Testing with k6. We cover key concepts, practical examples, and best practices to help you master this topic.
k6 is a modern load testing tool that uses JavaScript to script API scenarios, simulate virtual users, and collect performance metrics like response time, error rate, and requests per second.
What You'll Learn
- How to write k6 scripts for API load testing
- Configuring virtual users, duration, and ramp-up stages
- Interpreting key performance metrics
Why It Matters
APIs that perform well under light load may fail under production traffic. Load testing identifies bottlenecks, memory leaks, and concurrency issues before they affect users.
Real-World Use
A SaaS platform uses k6 to simulate 1000 concurrent users hitting their REST API. Tests reveal that the database connection pool maxes out at 500 connections, prompting a pool size increase before launch.
flowchart LR
A[k6 Script] --> B[Virtual Users]
B --> C[API Under Test]
C --> D[Metrics Collection]
D --> E[Threshold Evaluation]
E --> F[Pass/Breakpoint Report]
Basic Load Test Script
A simple k6 script that tests a GET endpoint with 10 virtual users.
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
vus: 10,
duration: "30s",
};
export default function () {
const res = http.get("https://api.example.com/products");
check(res, {
"status is 200": (r) => r.status === 200,
"response time < 500ms": (r) => r.timings.duration < 500,
});
sleep(1);
}
Expected output: k6 reports 100% check pass rate and average response time under 500ms.
Staged Ramp-Up
Gradually increase load to find the system's breaking point.
export const options = {
stages: [
{ duration: "2m", target: 50 },
{ duration: "3m", target: 100 },
{ duration: "2m", target: 200 },
{ duration: "1m", target: 0 },
],
thresholds: {
http_req_duration: ["p(95)<2000"],
http_req_failed: ["rate<0.01"],
},
};
Expected output: k6 gradually increases to 200 users and reports pass/fail against thresholds.
Testing a POST Endpoint
Load test a POST endpoint that creates resources.
export default function () {
const payload = JSON.stringify({
name: `User_${__VU}_${__ITER}`,
email: `user${__VU}@example.com`,
});
const res = http.post("https://api.example.com/users", payload, {
headers: { "Content-Type": "application/json" },
});
check(res, {
"status is 201": (r) => r.status === 201,
"response has id": (r) => JSON.parse(r.body).id !== undefined,
});
}
Expected output: All POST requests return 201 with a unique id.
Common Mistakes
| Mistake | Why It's Wrong |
|---|---|
| Testing without ramp-up | Immediate high load can trigger false throttling |
| Ignoring think time | Real users pause between actions; without sleep, tests are unrealistic |
| Running from a single machine | Network or machine limits skew results |
| Not resetting state between iterations | Shared state causes cross-iteration contamination |
| Testing only happy path | Edge cases like auth failure or validation errors go untested |
| Overlooking threshold evaluation | Metrics without thresholds have no pass/fail criteria |
| Not correlating metrics | Response time alone doesn't reveal the cause of slowdowns |
Practice Questions
- What is a virtual user in k6?
A: A simulated user that runs the
defaultfunction in a loop for the test duration. - How do you set a threshold for the 95th percentile response time?
A:
thresholds: { http_req_duration: ["p(95)<2000"] }— 95% of requests must complete under 2000ms. - What is the difference between
vusandstages? A:vussets a constant user count;stagesdefines a ramp-up/ramp-down schedule. - How does k6 handle cookies? A: k6 automatically manages cookies like a browser, storing and sending them per VU.
- What is the
__VUvariable? A: A built-in variable that returns the current virtual user number (1-indexed).
Challenge
Write a k6 script that ramps from 0 to 500 users over 5 minutes, holds for 2 minutes, then ramps down. Set thresholds: p(95) response time under 3 seconds and error rate under 0.5%.
FAQ
What is the difference between k6 and JMeter?
k6 is script-based (JavaScript), lightweight, and designed for CI/CD. JMeter is GUI-based and more feature-rich but harder to automate.
Can k6 test Graphql endpoints?
Yes. Send GraphQL queries as POST requests with JSON bodies, just like any HTTP endpoint.
How do you run k6 in CI/CD?
Use the official k6 Docker image (<a href="/devops/prometheus-grafana/">Grafana</a>/k6) in your pipeline and run k6 run script.js.
What metrics does k6 collect?
Key metrics: http_req_duration (response time), http_req_failed (error rate), http_reqs (throughput), vus (active users).
How do you output k6 results?
Use --out json for JSON, --out csv for CSV, or --out influxdb to send to InfluxDB for Grafana dashboards.
What is a breakpoint test?
A test that gradually increases load until the system fails, identifying the maximum capacity.
How do you test authenticated endpoints in k6?
Set auth headers in the default function: http.get(url, { headers: { Authorization: token } }).
Mini Project
Write a k6 test suite for an e-commerce API. Include endpoints: GET /products, POST /cart (add item), DELETE /cart/item, POST /checkout. Use a staged ramp-up from 10 to 200 users over 10 minutes. Set thresholds for response time and error rate. Output results as JSON.
What's Next
Now that you can load test APIs, learn API Security Testing to identify vulnerabilities in your endpoints.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro