Skip to main content

Grafana k6

A developer-centric load and performance testing tool scripted in JavaScript and executed in Go.

CategoryTesting & Mocking
PricingOpen source
Lifecycle stages
Testing
Updated2026-10-14

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, and setup/teardown hooks, so they review and version like any other code.
  • Checks and thresholds: check() validates individual responses without stopping the run; thresholds turn metrics such as http_req_duration and http_req_failed into 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'] and http_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-rate or ramping-arrival-rate keeps 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 single name tag so each ID does not become its own metric series.
  • Decide what counts as a failure. By default http_req_failed treats any status outside 200 to 399 as failed, so an expected 404 Not Found or 409 Conflict in the scenario inflates the error rate; set http.setResponseCallback(http.expectedStatuses(...)) to match the scenario.
  • Watch for 429 Too Many Requests and 503 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 sends Retry-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.