k6
Load testing written in JavaScript and run from a CLI — finding the breaking point before your users do.
“It’s fast” usually means “it’s fast for me, alone, on a warm cache.” The first honest measurement of a system arrives during a launch, and by then it’s a story rather than a test.
k6 makes the measurement cheap: tests are JavaScript, the runner is a single Go binary, and the output is the same percentiles you already track in Grafana. Grafana Labs maintains it; AGPL, free to run.
Install and run
brew install k6
// smoke.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10, // virtual users
duration: '30s',
thresholds: {
http_req_failed: ['rate<0.01'], // under 1% errors
http_req_duration: ['p(95)<500'], // p95 under 500ms
},
};
export default function () {
const res = http.get('https://staging.example.com/api/items');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
k6 run smoke.js
Thresholds are the feature. They turn a wall of numbers into a pass or fail, which means a load test can live in CI and block a merge rather than being a thing someone runs occasionally and interprets.
Shape the load to the question
export const options = {
stages: [
{ duration: '2m', target: 100 }, // ramp up
{ duration: '5m', target: 100 }, // hold — this is where you learn things
{ duration: '2m', target: 0 }, // ramp down
],
};
| Test | Shape | Question |
|---|---|---|
| Smoke | A few users, a minute | Does it work at all? Run on every deploy |
| Load | Expected peak, held | Does it meet its targets under normal busy? |
| Stress | Ramp past peak until it breaks | Where is the limit, and how does it fail? |
| Soak | Moderate load, hours | Do memory or connections leak? |
The hold phase matters more than the peak. Systems fail on the fifth minute of sustained load — connection pools exhaust, caches evict, autoscalers thrash — not in the first thirty seconds.
Read it against your dashboards
Run the test with your monitoring open. The client-side numbers tell you what users would feel; Prometheus tells you which resource ran out first. One without the other leaves you knowing that it broke without knowing why.
k6 run --out experimental-prometheus-rw script.js # push results in alongside
The rules that keep a load test honest
- Never point it at production without agreement. A load test is indistinguishable from an attack. Get consent, schedule it, warn whoever is on call — and check your provider’s policy, because some require notice.
- Test an environment shaped like production. Half the instances and an empty database will give you a number that means nothing.
- Use realistic data and think time. Ten users hammering one cached endpoint with no
sleep()measures your cache, not your system. - Fix one bottleneck at a time. Removing the first one just moves the queue to the next; re-run between changes or you won’t know which change helped.
Next
Testing the load is one thing; testing the failures is another → Chaos Engineering
Last updated 25 Aug 2026, 00:00 UTC.