“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
  ],
};
  
TestShapeQuestion
SmokeA few users, a minuteDoes it work at all? Run on every deploy
LoadExpected peak, heldDoes it meet its targets under normal busy?
StressRamp past peak until it breaksWhere is the limit, and how does it fail?
SoakModerate load, hoursDo 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. history