What is Grafana k6?
Grafana k6 is an open-source load testing tool maintained by Grafana Labs under the AGPL-3.0 license. The engine is written in Go and tests are scripts in JavaScript, or TypeScript run directly since k6 1.0, so a test is code that lives in a repository and runs in CI. Each script defines what a virtual user does, how many of them run and for how long, and the pass/fail criteria for the run. The same script runs locally with k6 run, distributed on Kubernetes, or on the paid Grafana Cloud k6 service.
Why use it in the API Lifecycle?
- Tests as code: Scripts are plain modules with
options, a default function per iteration, andsetup/teardownhooks, so they review and version like any other code. - Checks and thresholds:
check()validates individual responses without stopping the run;thresholdsturn metrics such ashttp_req_durationandhttp_req_failedinto pass/fail criteria, and a failed threshold makes k6 exit non-zero. - Workload models: Scenarios and executors cover both closed models (a fixed number of virtual users) and open models (a constant or ramping arrival rate), which matters when you want to know how an API behaves at a target request rate.
- Protocol coverage: HTTP/1.1 and HTTP/2, WebSockets and gRPC are built in, along with a browser module for front-end checks.
- Extensions: xk6 extensions add protocols and outputs that the core does not ship.
- Metrics output: Results go to the end-of-test summary or stream to external backends for correlation with server-side telemetry.
Best Practices
- Gate on thresholds, not on eyeballing the summary. A block such as
http_req_failed: ['rate<0.01']andhttp_req_duration: ['p(95)<300']makes the run fail the pipeline. Use percentiles, never the average, which hides the slow tail clients actually feel. - Model arrival rate when you are testing capacity. A closed model with a fixed number of virtual users slows its own request rate as the API slows down, which masks the problem;
constant-arrival-rateorramping-arrival-ratekeeps sending at the target rate and shows the queueing. - Tag requests by endpoint and set thresholds per tag, for example
'http_req_duration{name:create-order}': ['p(95)<500']. One aggregate latency number lets a slow write endpoint hide behind fast reads. Group URLs that contain IDs under a singlenametag so each ID does not become its own metric series. - Decide what counts as a failure. By default
http_req_failedtreats any status outside 200 to 399 as failed, so an expected404 Not Foundor409 Conflictin the scenario inflates the error rate; sethttp.setResponseCallback(http.expectedStatuses(...))to match the scenario. - Watch for
429 Too Many Requestsand503 Service Unavailable. If the test trips the API’s own rate limiting, you measured the limiter, not the service; either test with an exempt credential or treat the limiter’s behavior as the subject of the test, including whether it sendsRetry-After. - Load test an environment shaped like production, with production-like data volumes, and never point a test at a third-party API you do not own. Correlate the run with server-side metrics and traces (see Observability and Tracing) so a latency spike can be attributed to a cause.
- Keep a small smoke version of the same script, a handful of virtual users for a minute, and run it on every merge. The full load profile can run on a schedule.