RepoPilotOpen in app →

grafana/k6

A modern load testing tool, using Go and JavaScript

Healthy

Healthy across the board

worst of 4 axes
Use as dependencyConcerns

copyleft license (AGPL-3.0) — review compatibility

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit today
  • 15 active contributors
  • Distributed ownership (top contributor 24% of recent commits)
Show 4 more →
  • AGPL-3.0 licensed
  • CI configured
  • Tests present
  • AGPL-3.0 is copyleft — check downstream compatibility
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/grafana/k6)](https://repopilot.app/r/grafana/k6)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/grafana/k6 on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: grafana/k6

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/grafana/k6 shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit today
  • 15 active contributors
  • Distributed ownership (top contributor 24% of recent commits)
  • AGPL-3.0 licensed
  • CI configured
  • Tests present
  • ⚠ AGPL-3.0 is copyleft — check downstream compatibility

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live grafana/k6 repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/grafana/k6.

What it runs against: a local clone of grafana/k6 — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in grafana/k6 | Confirms the artifact applies here, not a fork | | 2 | License is still AGPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>grafana/k6</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of grafana/k6. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/grafana/k6.git
#   cd k6
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of grafana/k6 and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "grafana/k6(\\.git)?\\b" \\
  && ok "origin remote is grafana/k6" \\
  || miss "origin remote is not grafana/k6 (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is AGPL-3.0" \\
  || miss "license drift — was AGPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "cmd/execute.go" \\
  && ok "cmd/execute.go" \\
  || miss "missing critical file: cmd/execute.go"
test -f "api/v1/routes.go" \\
  && ok "api/v1/routes.go" \\
  || miss "missing critical file: api/v1/routes.go"
test -f "cloudapi/api.go" \\
  && ok "cloudapi/api.go" \\
  || miss "missing critical file: cloudapi/api.go"
test -f "cloudapi/client.go" \\
  && ok "cloudapi/client.go" \\
  || miss "missing critical file: cloudapi/client.go"
test -f "cmd/state/state.go" \\
  && ok "cmd/state/state.go" \\
  || miss "missing critical file: cmd/state/state.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/grafana/k6"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

k6 is a modern load testing tool written in Go with an embedded JavaScript engine (Sobek) that lets developers write performance tests as code. It's designed to simulate realistic traffic patterns across HTTP, WebSockets, gRPC, and browser-based protocols, combining Go's performance with JavaScript's familiar scripting experience for load generation and metrics collection. Monolithic Go application with a clear separation: core execution engine in the main Go codebase, JavaScript runtime bindings through Sobek (grafana/sobek), protocol implementations for HTTP/WebSocket/gRPC/browser modules, and CLI handling through cmd/ likely patterns. The ./api/v1 directory suggests a REST API layer. GitHub Actions workflows in .github/workflows/ orchestrate testing across browser environments, xk6 extensions, and TC39 compliance.

👥Who it's for

DevOps engineers, performance testers, and backend developers who need to conduct load testing as part of CI/CD pipelines. They use k6 to write reusable, version-controlled test scripts and integrate results with monitoring tools like Grafana Cloud without needing to learn a specialized DSL.

🌱Maturity & risk

Highly mature and production-ready. The codebase is dominated by 5.3M lines of Go with comprehensive CI/CD workflows (.github/workflows/test.yml, .github/workflows/build.yml, lint.yml), active GitHub Actions integration, codecov tracking, and well-established release infrastructure visible in .github/ISSUE_TEMPLATE/release.md. The project is actively maintained by Grafana Labs with consistent contribution patterns.

Low risk for a load testing tool. Dependencies are well-managed (gRPC, OpenTelemetry, Sobek are all standard packages from reputable sources). The main risk is the tight coupling to Sobek (the custom JavaScript runtime in grafana/sobek) which could limit upstream JavaScript compatibility. No single-maintainer risk given Grafana Labs backing, but xk6 extension ecosystem dependency adds complexity for custom extensions.

Active areas of work

Active development on browser automation (browser_e2e.yml workflow), xk6 extension testing (.github/workflows/xk6.yml), and TC39 JavaScript compliance (tc39.yml). The codebase tracks code generation tasks (summary-code-generation.yml), maintains PackageRelease automation, and actively tests cross-platform builds. Recent focus appears to be on browser protocol support and extension ecosystem stability.

🚀Get running

Clone the repo: git clone https://github.com/grafana/k6.git && cd k6. Install dependencies: go mod download. Build the binary: make build (Makefile present). Run tests: make test. The project uses Go 1.25.0 (visible in go.mod versions), and the Makefile will be your primary interface for building and testing locally.

Daily commands: make build to compile the k6 binary. Run tests with make test. For local development against the latest code, build a test k6 script (JavaScript file) and execute it with ./k6 run your-test.js. GitHub Actions workflows show go test ./... and go build ./cmd/k6 as standard patterns. The project uses Docker for isolated testing (Dockerfile present).

🗺️Map of the codebase

  • cmd/execute.go — Main entry point for k6 CLI execution; orchestrates test lifecycle from parsing to metrics collection
  • api/v1/routes.go — Core REST API router defining all control surface endpoints for load test management
  • cloudapi/api.go — Cloud backend integration layer handling test orchestration, result streaming, and distributed execution
  • cloudapi/client.go — HTTP client for Grafana Cloud communication; critical for remote test execution and metrics upload
  • cmd/state/state.go — Global execution state machine managing test phases, VU lifecycle, and runtime context
  • Makefile — Build orchestration; defines compilation targets, test runners, and cross-platform distribution
  • go.mod — Dependency manifest pinning Go version (1.25.0) and critical modules like sobek (JS runtime) and grpc-gateway

🛠️How to make changes

Add a New REST API Endpoint

  1. Define the handler function in the appropriate routes file (e.g., api/v1/status_routes.go for status-related endpoints) (api/v1/status_routes.go)
  2. Register the route in api/v1/routes.go by adding a mux.HandleFunc() call with the correct HTTP method (api/v1/routes.go)
  3. Implement JSON marshaling if needed using the _jsonapi.go pattern (e.g., api/v1/status_jsonapi.go) (api/v1/status_jsonapi.go)
  4. Add integration tests in api/v1/status_routes_test.go following existing handler test patterns (api/v1/status_routes_test.go)

Add Cloud API Integration

  1. Add the new API method to cloudapi/api.go, following the existing pattern of authenticated HTTP calls (cloudapi/api.go)
  2. Define Cloud client method in cloudapi/client.go using the authenticated HTTP wrapper (cloudapi/client.go)
  3. Update cloudapi/config.go if new configuration fields are required (cloudapi/config.go)
  4. Add unit tests in cloudapi/api_test.go covering success and error scenarios (cloudapi/api_test.go)

Add a New Metric Type

  1. Extend the Metric struct in api/v1/metric.go with new fields and aggregation logic (api/v1/metric.go)
  2. Update metric JSON marshaling in api/v1/metric_jsonapi.go to serialize the new fields (api/v1/metric_jsonapi.go)
  3. If exposing via the metrics endpoint, update api/v1/metric_routes.go to include new metric in streaming response (api/v1/metric_routes.go)
  4. Add test coverage in api/v1/metric_routes_test.go and api/v1/metric_test.go (api/v1/metric_test.go)

Extend Test Execution State Machine

  1. Add new state enum or phase constant to cmd/state/state.go (cmd/state/state.go)
  2. Update the state transition logic in cmd/state/state.go to handle the new phase (cmd/state/state.go)
  3. Export the new state via api/v1/status.go so the REST API can report it (api/v1/status.go)
  4. Add test cases in cmd/state/ for new state transitions and edge cases (cmd/tests/global_state.go)

🔧Why these technologies

  • Go 1.25.0 — Native compilation to single binary for cross-platform distribution; efficient concurrency primitives (goroutines) for managing thousands of VUs
  • Sobek (JavaScript VM) — Allows load tests to be written in JavaScript for developer familiarity; embedded in Go binary for portability
  • REST API (mux-based) — Simple HTTP interface for real-time test control and metrics collection without external dependencies; integrates with Grafana dashboards
  • gRPC-Gateway (api/v1) — Bridges gRPC and REST; enables both low-latency distributed communication and human-friendly HTTP endpoints
  • Grafana Cloud backend — Centralized orchestration for distributed test runs across regions; result aggregation and historical storage

⚖️Trade-offs already made

  • Embedded JavaScript runtime (Sobek) instead of Node.js

    • Why: Single binary simplicity and zero external process overhead
    • Consequence: Limited to JS feature set; no npm package ecosystem; custom k6 API required
  • Local REST API for control vs. only CLI arguments

    • Why: Enables live VU scaling, pause/resume, and real-time metric inspection without test restart
    • Consequence: Added complexity; potential race conditions between API and CLI state; requires careful lifecycle management
  • Metrics pushed to Cloud vs. polled from local API

    • Why: Distributed tests cannot block on central aggregation; cloud backend handles cross-region merging
    • Consequence: Slightly stale metrics (~100–200ms latency); eventual consistency model; retry/dedup logic needed
  • State machine in cmd/state/state.go as single source of truth

    • Why: Avoids divergence between API endpoint state and actual executor state
    • Consequence: API must always query state machine; state transitions must be serialized; potential bottleneck under high concurrency

🚫Non-goals (don't propose these)

  • Real-time streaming of individual request payloads (only aggregated metrics)
  • Built-in authentication or TLS termination (delegates to reverse proxy or Cloud)
  • Stateful test resume/checkpoint across restarts (tests are ephemeral)
  • Multi-user test

🪤Traps & gotchas

No single obvious trap, but several subtleties: (1) The JavaScript runtime is not standard V8 but a custom Sobek fork, so some JavaScript features or performance characteristics differ from Node.js. (2) xk6 extension building requires a local k6 checkout to compile against, not just binary dependencies. (3) The project likely requires specific Go version constraints (1.25.0 in go.mod) and may fail with significantly older or newer versions. (4) Browser tests require additional setup (.github/actions/test-browser/action.yml suggests external service dependencies). Check the .github/workflows/browser_e2e.yml for environment setup details if working on browser features.

🏗️Architecture

💡Concepts to learn

  • Virtual User (VU) Model — k6's core abstraction for load generation—understanding how VUs run concurrently and maintain state is essential to writing correct load tests and predicting tool behavior
  • Sobek JavaScript Runtime (GraalVM-based) — k6 uses a custom JavaScript engine rather than V8; understanding its differences in feature support and performance characteristics is critical for advanced JavaScript use
  • Metrics Collection and Time-Series Aggregation — k6's architecture pipelines raw metrics through aggregators and exporters to backends like Grafana Cloud; understanding this flow is necessary for custom metric plugins and debugging metric anomalies
  • xk6 Extension System (Go Plugin Pattern) — k6's extensibility relies on dynamically loaded Go modules compiled against the k6 codebase; this architecture pattern enables custom protocols and modules without core changes
  • gRPC and Protocol Buffer Integration — k6 supports gRPC load testing through compiled protocol buffers and gRPC-gateway; essential for testing modern microservices and understanding how the tool abstracts protocol complexity
  • Browser Automation and Chromium Integration — k6's browser module drives real Chromium instances for realistic load testing; understanding the architectural boundary between synthetic load and real browser behavior is key to avoiding test misuse
  • OpenTelemetry Instrumentation — k6 exports traces via OpenTelemetry for observability; contributors touching the metrics or tracing code must understand OTEL's SDK architecture and exporter patterns
  • grafana/sobek — The custom JavaScript runtime engine that k6 depends on; forking or improving this directly impacts k6's JavaScript compatibility and performance
  • grafana/xk6 — The extension toolkit for building custom k6 modules in Go; essential companion for users wanting to extend k6 beyond built-in protocols
  • loadimpact/k6-docs — The official documentation repository for k6; where users learn the API and best practices that developers here implement
  • apache/jmeter — A direct competitor for load testing; k6 positions itself as a modern alternative with better developer experience and code-as-test philosophy
  • tsenart/vegeta — A lightweight HTTP load testing tool in Go; represents an alternative lightweight approach that k6 builds upon with more features and extensibility

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for api/v1 routes handlers

The api/v1 directory contains multiple route handlers (group_routes.go, metric_routes.go, setup_teardown_routes.go) with corresponding test files, but test coverage appears incomplete. The *_routes_test.go files likely need expanded coverage for edge cases, error handling, and HTTP status codes. This is critical for a load testing tool's control API reliability.

  • [ ] Review existing tests in api/v1/group_routes_test.go, api/v1/metric_routes_test.go, api/v1/setup_teardown_routes_test.go
  • [ ] Identify untested code paths in corresponding handler files (group_routes.go, metric_routes.go, setup_teardown_routes.go)
  • [ ] Add table-driven tests for error scenarios (invalid input, missing fields, concurrent requests)
  • [ ] Ensure coverage for JSON API serialization in group_jsonapi.go and metric_jsonapi.go
  • [ ] Add tests verifying proper error responses from api/v1/errors.go

Create GitHub Action workflow for xk6 extension compatibility testing

The repo contains xk6-tests workflows (.github/workflows/xk6-tests/ and xk6.yml) with test modules for JavaScript extensions and custom outputs, but they appear scattered. Consolidate and enhance the workflow to automatically test popular xk6 extensions against new k6 versions, preventing breakage for the extension ecosystem.

  • [ ] Review current xk6.yml and xk6-tests/xk6-js-test/jstest.go and xk6-tests/xk6-output-test/outputtest.go
  • [ ] Create a comprehensive workflow that builds k6 with multiple popular xk6 extensions (xk6-http, xk6-websockets, etc.)
  • [ ] Add matrix strategy to test against multiple Go versions matching go.mod version constraints
  • [ ] Configure workflow to report compatibility status and create issues for breaking changes
  • [ ] Document expected extension versions in CONTRIBUTING.md or Dependencies.md

Add api/v1/client integration tests covering all metric and status operations

The api/v1/client directory contains client.go, metrics.go, and status.go that communicate with the k6 REST API, but lacks comprehensive integration tests. Adding these tests ensures the client library correctly handles server responses, connection errors, and timeout scenarios—critical for tools integrating with k6.

  • [ ] Review api/v1/client/client.go, metrics.go, and status.go for all exported methods
  • [ ] Create api/v1/client/client_integration_test.go with table-driven tests covering each client method
  • [ ] Mock the k6 API server responses based on api/v1/metric_routes.go and api/v1/group_routes.go specifications
  • [ ] Add tests for error scenarios: connection refused, malformed JSON responses, HTTP 4xx/5xx errors
  • [ ] Test concurrent client calls and verify proper cleanup/resource management

🌿Good first issues

  • Add missing test coverage for the api/v1 REST endpoint layer—check for gaps in api/v1 *_test.go files compared to actual handlers and submit focused unit tests
  • Improve documentation for the xk6 extension system by examining .github/workflows/xk6-tests/ and adding clear examples to the docs/ folder for extending k6 with custom Go modules
  • Add validation and error handling tests for edge cases in protocol handlers (HTTP, WebSocket, gRPC)—create test files demonstrating malformed requests, timeout scenarios, and protocol violations

Top contributors

Click to expand

📝Recent commits

Click to expand
  • aeed358 — chore(deps): update go toolchain directive to v1.25.10 (renovate-sh-app[bot])
  • 259d652 — chore(deps): update golang docker tag to v1.26.3 (renovate-sh-app[bot])
  • df94e5d — fix test expectation for updated semver constraint error message format (mstoykov)
  • 6fd26a3 — fix(deps): update module github.com/masterminds/semver/v3 to v3.5.0 (renovate-sh-app[bot])
  • 2766254 — ci: only move :vN when releasing the latest tag on that major (mstoykov)
  • 7f739f1 — ci: avoid promoting pre-releases and old majors to latest (mstoykov)
  • 8eb7fed — chore(deps): update module golang.org/x/net to v0.53.0 [security] (renovate-sh-app[bot])
  • 120ab8d — fix(deps): update github.com/grafana/sobek digest to a66d479 (renovate-sh-app[bot])
  • 51ab8a8 — fix(deps): update module github.com/mattn/go-isatty to v0.0.22 (renovate-sh-app[bot])
  • 46e48e9 — Merge pull request #5853 from grafana/drop-easyjson (joanlopez)

🔒Security observations

Failed to generate security analysis.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · grafana/k6 — RepoPilot