k6 v2.0.0 is here 🎉!
k6 v2.0.0 is the final release of the v2 major version, completing the cleanup of deprecated APIs, old commands, and obsolete configuration options that was started with v2.0.0-rc1. If you were already running the release candidate, this release includes a handful of additional changes on top — they are marked with (new since v2.0.0-rc1) throughout these notes.
Here's a glimpse of what's changed in this release:
- The Go module path has changed to
go.k6.io/k6/v2— all extensions must update their import paths to be compatible with v2. - Removal of all long-deprecated CLI commands and flags:
k6 login,k6 pause,k6 resume,k6 scale,k6 status,--no-summary,--upload-only, and more. - The
externally-controlledexecutor has been removed — scripts usingexecutor: externally-controlledwill no longer run. - Cloud run non-threshold aborts (aborted by user, system, timeout, etc.) now return exit code
97instead of0. options.ext.loadimpactis no longer supported — useoptions.cloud.k6/experimental/redismodule has been removed.- The
k6 cloud script.jspositional form has been fully removed — usek6 cloud run script.js. - A stack is now required for all
k6 cloudcommands — the previous fallback to the first available stack has been removed. - The web-vitals library has been updated to v5.1.0, removing the deprecated FID metric.
- (new since v2.0.0-rc1) easyjson has been dropped in favor of stdlib
encoding/json— extension authors relying on easyjson-generated methods on k6 types must update. - (new since v2.0.0-rc1) The k6 HTTP API server no longer starts by default — pass
--addressto enable it. - (new since v2.0.0-rc1) New
k6 cloud project listcommand to list Grafana Cloud k6 projects. - (new since v2.0.0-rc1) Cloud secrets are now automatically available in
k6 cloud run --local-execution; use--no-cloud-secretsto opt out.
Breaking changes
These are changes that require you to update your scripts, CI/CD pipelines, or configuration files before upgrading.
Go module path changed to go.k6.io/k6/v2 #5777
Following the Go module versioning conventions, the k6 module path has changed from go.k6.io/k6 to go.k6.io/k6/v2.
Any extension or external package that imports go.k6.io/k6 must update all import paths to go.k6.io/k6/v2. For the vast majority of extensions this is the only change needed — a mechanical find-and-replace across the codebase:
go.k6.io/k6/ → go.k6.io/k6/v2/
For example:
// Before
import "go.k6.io/k6/js/modules"
// After
import "go.k6.io/k6/v2/js/modules"Removed CLI commands #5653
The following commands for controlling a running test have been removed. They have not been functional for most use cases since the REST API they relied on was limited to specific execution modes:
k6 pausek6 resumek6 scalek6 status
Migration: There is no replacement. These commands relied on the externally-controlled executor, which has also been removed in v2.0.0 (see below).
Removed externally-controlled executor #5846
The externally-controlled executor has been removed. It was legacy code from an older k6 Cloud architecture that allowed external systems to scale VUs and pause/resume a running test via the k6 REST API — the capability that k6 pause, k6 resume, k6 scale, and k6 status relied on.
Migration: There is no replacement. Any test script with executor: externally-controlled will fail to start. Migrate to a different executor based on the desired load profile (e.g., ramping-vus, constant-vus, constant-arrival-rate).
Removed k6 login command #5134
The top-level k6 login command and its subcommands (k6 login cloud, k6 login influxdb) have been removed.
Migration:
- Replace
k6 login cloud→k6 cloud login - InfluxDB authentication is no longer configurable via a login command. Use environment variables such as
K6_INFLUXDB_*to configure the InfluxDB output directly.
Removed k6 cloud script.js positional form #5624, #5912 (completed in v2.0.0)
The old positional-argument form k6 cloud script.js has been fully removed. In v2.0.0-rc1 it was changed to show help instead of running; in v2.0.0 the deprecated command handler itself has been removed entirely. The run subcommand has been the recommended path since k6 cloud run was introduced.
Migration: Replace k6 cloud script.js with k6 cloud run script.js.
Removed --upload-only flag #5844
The --upload-only flag on the k6 cloud command has been removed.
Migration: Use k6 cloud upload script.js to upload a test without running it.
Removed --no-summary flag #5729
The --no-summary flag has been removed.
Migration: Replace --no-summary with --summary-mode=disabled.
Removed --summary-mode=legacy #5730
The legacy value for --summary-mode has been removed.
Migration: There is no direct equivalent — the new summary format is different from the legacy one. Review the available summary modes and choose the one that best fits your needs: compact (the default) or full for more detailed output.
Removed options.ext.loadimpact support #5774
The options.ext.loadimpact configuration block in test scripts is no longer supported.
Migration: Move all cloud-related configuration from options.ext.loadimpact to options.cloud:
// Before
export const options = {
ext: {
loadimpact: {
projectID: 12345,
name: "My Test",
},
},
};
// After
export const options = {
cloud: {
projectID: 12345,
name: "My Test",
},
};Removed k6/experimental/redis module #5485
The k6/experimental/redis module has been removed from the k6 core binary. It was shipped as an experiment and has not been promoted to stable.
Migration: Change your import from k6/experimental/redis to k6/x/redis. With auto-extension-resolution, k6 will automatically provision the xk6-redis extension when it sees the k6/x/redis import.
Removed ExporterType option from OpenTelemetry output #5754
The deprecated exporterType configuration option for the OpenTelemetry output has been removed.
Migration: Replace K6_OTEL_EXPORTER_TYPE with K6_OTEL_EXPORTER_PROTOCOL. The accepted values are grpc and http/protobuf.
Removed SingleCounterForRate option from OpenTelemetry output #5830
The temporary SingleCounterForRate escape-hatch option for the OpenTelemetry output has been removed. It was introduced as a one-release migration aid in #5164 to let users revert to the old pair-of-counters format (<metric>.occurred + <metric>.total) while upgrading. Rate metrics are now always exported as a single counter with a condition attribute (nonzero/zero).
Migration: Remove any K6_OTEL_SINGLE_COUNTER_FOR_RATE=true configuration. If you were using the old pair-of-counters format, update your dashboards and queries to use the single counter with condition attribute instead.
Removed K6_BINARY_PROVISIONING environment variable #5734
The K6_BINARY_PROVISIONING environment variable, deprecated in v1.2.0, has been removed.
Migration: Remove K6_BINARY_PROVISIONING from your environment. Auto-extension-resolution is enabled by default; K6_AUTO_EXTENSION_RESOLUTION only needs to be set explicitly if you want to disable it.
Removed K6_ENABLE_COMMUNITY_EXTENSIONS environment variable #5733
The K6_ENABLE_COMMUNITY_EXTENSIONS environment variable has been removed. The community and cloud extension catalogs were merged server-side, making this flag a no-op since the catalogs were unified.
Migration: Remove K6_ENABLE_COMMUNITY_EXTENSIONS from your environment. Community extensions are now resolved through the default build service URL automatically.
Stack is now required for all k6 cloud commands #5833
Providing a stack is now mandatory for all k6 cloud commands (k6 cloud run, k6 cloud upload, k6 cloud run --local-execution). Previously, omitting a stack would fall back to the first available stack with a deprecation warning — that fallback has been removed. Likewise, k6 cloud login now requires both a token and a stack; passing one without the other fails with an explicit error.
Migration: Run k6 cloud login which will ask you for the stack and setup correctly for the new version of k6. Alternatively, the K6_CLOUD_STACK_ID environment variable, or the stackID script option are available to be set before running any k6 cloud command .
Removed legacy configuration file path migration #5609
k6 no longer automatically migrates configuration files from the old {USER_CONFIG_DIR}/loadimpact/config.json path introduced before k6 v1.0.0.
Migration: If you still have a config file at the old path, move it to {USER_CONFIG_DIR}/k6/config.json. You can also re-run k6 cloud login to regenerate the file at the correct location.
Cloud run non-threshold aborts now exit with code 97 #5769
Previously, most cloud abort scenarios returned an exit code of 0, making it impossible for CI pipelines to distinguish a failed run from a successful one. These scenarios now return exit code 97.
| Scenario | Before | After |
|---|---|---|
| Finished | 0
| 0
|
| Aborted by threshold | 99
| 99
|
| Aborted by system, limit, script error, user, or timeout | 0
| 97
|
Migration: Review any CI pipeline logic that treats exit code 0 as success for cloud runs. Cloud runs that abort for reasons other than threshold violations will now return exit code 97.
Browser: FID metric removed, web vitals updated to v5.1.0 #5661
The browser_web_vital_fid metric has been removed. FID (First Input Delay) was deprecated as a Core Web Vital and replaced by INP (Interaction to Next Paint). The embedded web-vitals library has been updated from v3 to v5.1.0, which reflects this change.
Migration: Update any dashboards, alerts, or threshold rules that reference browser_web_vital_fid to use browser_web_vital_inp instead.
Dropped easyjson in favor of stdlib encoding/json (new since v2.0.0-rc1) #5853
k6 no longer uses easyjson for JSON serialization. Several types in the public Go API previously had easyjson-generated MarshalJSON/UnmarshalJSON methods; those are now gone, replaced by stdlib encoding/json. This change was intentionally held until v2 to avoid a breaking change mid-cycle.
Migration: Extension authors who relied on easyjson-generated methods on k6 types should remove those dependencies. Standard encoding/json marshaling applies to all affected types.
HTTP API server no longer starts by default (new since v2.0.0-rc1) #5876
The k6 HTTP API server no longer starts automatically. Previously, k6 always listened on localhost:6565 unless opted out. The server now only starts when an address is explicitly provided via the --address flag or the K6_ADDRESS environment variable.
Migration: If you use the k6 REST API, pass --address=localhost:6565 (or any address) to re-enable the server.
New features
Cloud secret source #5738
A new built-in secret source, cloud, allows k6 scripts to retrieve secrets stored in Grafana Cloud directly during local execution. Pass --secret-source=cloud when running k6 cloud run --local-execution to make cloud-managed secrets available to your script via secrets.get(). Thanks, @vortegatorres!
k6 cloud run --local-execution --secret-source=cloud script.jsCloud secret source enabled by default for local execution (new since v2.0.0-rc1) #5875
--secret-source=cloud is no longer required. When running k6 cloud run --local-execution, the cloud secret source is now automatically available and secrets.get() works out of the box.
To opt out, pass --no-cloud-secrets:
k6 cloud run --local-execution --no-cloud-secrets script.jsk6 cloud project list command (new since v2.0.0-rc1) #5650
A new k6 cloud project command group has been added, with a k6 cloud project list subcommand for listing Grafana Cloud k6 projects. The output supports both human-readable table format and JSON (--format=json).
k6 cloud project list
k6 cloud project list --format=jsonExtension tab-completion provisioning #5761
When using shell tab-completion, pressing TAB after a fully-typed extension name (e.g. k6 x docs <TAB>) will now automatically provision a custom binary with that extension and delegate the completion request to it. This means extension-specific flags and subcommands are available via tab-completion without any manual setup.
Pre-manifest extension dependencies captured in archive metadata #5819
When creating a k6 archive (k6 archive), extension dependency information is now captured in metadata.json under a "dependencies" field, using the constraints declared by the script before any external manifest overrides are applied. This ensures that k6/x/ imports are preserved correctly during auto-extension-resolution re-execution.
UX improvements and enhancements
- #5815 Warns when
http.get()orhttp.head()receive extra arguments that are silently ignored, helping catch common scripting mistakes. Thanks, @moko-poi! - #5657 Adds automatic retries to
newAction-based Locator APIs in the browser module, improving reliability of browser tests. Thanks, @janHildebrandt98! - #5779 Adds a
k6 x docshint to the main k6 help output for built-in documentation discovery. Thanks, @Reranko05! - #5788 Adds a
k6 x explorehint to the main k6 help output for extension discovery. - (new since v2.0.0-rc1) #5869 Improves cloud authentication error messages — instead of a single generic error, k6 now reports specifically whether a token or a stack ID is missing.
- (new since v2.0.0-rc1) #5845 Wires k6provider's structured logging into k6's logger. Provisioning operations (artifact resolution, cache hits, downloads, retries, and cache pruning) now appear in k6's log output at the correct level.
- (new since v2.0.0-rc1) Exposes the host k6 version to provisioned subcommands via
K6_PROVISION_HOST_VERSION, so extension subcommands can correctly identify the caller's k6 version when showing docs or feature information. - (new since v2.0.0-rc1) Tab completion no longer blocks on a build when the requested extension binary is not in the local cache — completions bail out instantly on a cache miss instead of waiting 10–30 seconds.
Bug fixes
- #5855 Fixes auto-extension-resolution incorrectly triggering binary provisioning when a script manifest specifies a dependency as a Go module pseudo-version (
v0.0.0+shaorv0.0.0-timestamp-sha), even when the running binary already satisfied the constraint. - #5769 Fixes several
k6 cloud runTUI issues: ghost duplicate progress bars appearing after the run finishes, a timer that stalled and then jumped to 100%, and a stale timer racing with the status line. - #5814 Fixes
k6 cloud run --local-executionignoringK6_CLOUD_PUSH_REF_IDand unconditionally creating a new test run instead of reusing the provided run ID. Thanks, @Reranko05! - #5716 Fixes WebSocket
bufferedAmountnot being incremented when sending TypedArrays, causing it to go negative. Thanks, @prakharbirla-ng! - #5630 Fixes duplicate redirect request metric emissions in the browser module, where each redirect was incorrectly emitting metrics for all prior redirects in the chain.
- #5786 Fixes swapped Min and Max values for Gauge metrics in Cloud output v2, which caused incorrect peak and floor values in cloud test result queries. Thanks, @esquonk!
- #5785 Fixes a race condition in the browser module's
handleExitEventwhereDone()was signalled before the subscription was removed, causing tests to hang until the timeout. - #5574 Fixes position parser for base pointer options. Thanks, @chrismooreproductions!
- (new since v2.0.0-rc1) #5905 Fixes a deadlock where WebSocket connections hang forever during teardown when the server sends pings. A server ping arriving during shutdown could permanently stall the k6 process.
- (new since v2.0.0-rc1) #5923 Fixes a nil pointer panic in
ElementHandle.DefaultTimeout(and any method that calls it, such asGetAttribute) when invoked on a nil or partially-initialized handle. Thanks, @SAY-5! - (new since v2.0.0-rc1) #5620 Preserves context cancellation causes across the scheduler, browser, and secret-source layers, improving the accuracy of error messages surfaced when a test is interrupted. Thanks, @LBaronceli!
Maintenance and internal improvements
- #5847 Moves
TaskQueuefrom the externalgithub.com/mstoykov/k6-taskqueue-libintointernal/js/taskqueue, eliminating an awkward reverse dependency where the library's own tests depended on k6. - #5775 Moves xk6-dashboard source code into
internal/dashboard, making the web dashboard a built-in part of the k6 binary without requiring a separate extension. The dashboard is available viak6 run --out=web-dashboard. - #5703, #5818, #5817 Uses Go's
synctestpackage withinlib/executor, eventloop, timer,PeriodicFlusher,output/cloud, andoutput/cloud/expv2tests for virtualized time, improving test determinism and CI speed. - #5778 Bumps Ubuntu CI runners to 24.04 and always installs Chromium for browser tests.
- #5826, #5827 Updates
go.opentelemetry.io/otel/exporters/otlp/otlptracehttpandotlpmetrichttptov1.43.0[security], adding a 4 MiB response body cap to mitigate memory exhaustion from misconfigured or malicious servers. - #5669, #5911 Updates
go.opentelemetry.io/otelpackages. - #5740, #5796, #5910 Updates
github.com/grafana/sobekdigest. - #5783, #5838, #5862 Updates
github.com/grafana/k6-cloud-openapi-client-go. - #5616, #5805 Updates
github.com/evanw/esbuildtov0.28.0. - #5667 Updates golangci-lint.
- #5799 Updates
buf.build/gen/go/prometheusprotobuf. - #5800 Updates
github.com/andybalholm/brotlitov1.2.1. - #5804 Updates
examples/dependencies. - #5806 Updates
github.com/fatih/colortov1.19.0. - #5807 Updates
github.com/puerkitobio/goquerytov1.12.0. - #5840, #5931 Updates
github.com/mattn/go-isattytov0.0.22. - #5857, #5950 Updates Go to
v1.25.10. - #5863, #5880, #5908 Updates
github.com/grafana/k6providertov0.5.0. - #5670 Updates GitHub artifact actions (major).
- #5693 Updates
crazy-max/ghaction-chocolateytov4. - #5706 Updates
actions/setup-goto4a36011. - #5707 Updates
anchore/sbom-actiontov0.24.0. - #5718, #5861 Updates
github/codeql-actiontov4.35.2. - #5720, #5802 Updates
docker/login-actiontov4.1.0. - #5771, #5798 Updates
grafana/shared-workflowsactions. - #5836 Updates
actions/upload-artifact. - #5809, #5839, #5951 Updates the Docker base image tags (Debian to v13, Go to
v1.26.3). - #5872 Fixes v6 cloud client losing the request body when retrying after a
Connection: closeresponse. - #5871 Returns an accurate error from the v6 cloud client when a test name lookup returns no results.
- #5751 Updates
github.com/klauspost/compresstov1.18.5. - #5841 Updates
golang.org/xpackages. - #5860 Updates Alpine Docker image to
v3.23.4. - (new since v2.0.0-rc1) #5864 Configures the v1 release branch to receive security updates via Renovate.
- (new since v2.0.0-rc1) #5891 Sets
K6ModPathto the v2 module path in the k6provider config so that k6 v2 correctly signals to k6build which module to resolve against (go.k6.io/k6/v2). - (new since v2.0.0-rc1) #5947 Reworks the release workflow so pre-releases and older-major maintenance releases no longer claim Docker
:latestor the GitHub "Latest release" marker. Adds a floating:vNDocker tag (e.g.grafana/k6:v1) for users who want to pin to a major line. - (new since v2.0.0-rc1) #5945 Updates
golang.org/x/nettov0.53.0[security] (CVE-2026-33814). - (new since v2.0.0-rc1) #5932 Updates
github.com/Masterminds/semver/v3tov3.5.0. - (new since v2.0.0-rc1) #5966 Bumps
github.com/Azure/go-ntlmssptov0.1.1. - (new since v2.0.0-rc1) #5965 Bumps the Go version used by the xk6 test workflows to appease security scanners.
External contributors
A huge thank you to the external contributors who helped during this release: @moko-poi, @janHildebrandt98, @Reranko05, @prakharbirla-ng, @esquonk, @chrismooreproductions, @vortegatorres, @SAY-5, and @LBaronceli! 🙏