release notes/v2.0.0-rc1.md
k6 v2.0.0-rc1 is here 🎉!
This release marks the first release candidate for k6 v2.0.0 — a major version that completes a long-running cleanup of deprecated APIs, old commands, and obsolete configuration options. Like the v1.0.0-rc1 before it, the purpose of this release is to give the community a chance to test the upgrade path, identify any issues, and migrate scripts or workflows affected by breaking changes. If you encounter any problems, please report them.
Here's a glimpse of what's changed in this release:
go.k6.io/k6/v2 — all extensions must update their import paths to be compatible with v2.k6 login, k6 pause, k6 resume, k6 scale, k6 status, --no-summary, --upload-only, and more.externally-controlled executor has been removed — scripts using executor: externally-controlled will no longer run.97 instead of 0.options.ext.loadimpact is no longer supported — use options.cloud.k6/experimental/redis module has been removed.k6 cloud command now shows help by default instead of attempting to run.k6 cloud commands — the previous fallback to the first available stack has been removed.These are changes that require you to update your scripts, CI/CD pipelines, or configuration files before upgrading.
go.k6.io/k6/v2 #5777Following 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"
As a result, no existing extensions will be compatible with v2.0.0-rc1. As we move toward the final v2.0.0 release, we expect most extensions to either already support the new path or to do so shortly after.
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 statusMigration: There is no replacement. These commands relied on the externally-controlled executor, which has also been removed in v2.0.0 (see below).
externally-controlled executor #5846The 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).
k6 login command #5134The top-level k6 login command and its subcommands (k6 login cloud, k6 login influxdb) have been removed.
Migration:
k6 login cloud → k6 cloud loginK6_INFLUXDB_* to configure the InfluxDB output directly.k6 cloud script.js no longer runs a test #5624Running k6 cloud without an explicit subcommand (i.e., the old positional-argument form k6 cloud script.js) now shows the help output instead of attempting to run the test. The run subcommand was already the recommended path since k6 cloud run was introduced.
Migration: Replace k6 cloud script.js with k6 cloud run script.js.
--upload-only flag #5844The --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.
--no-summary flag #5729The --no-summary flag has been removed.
Migration: Replace --no-summary with --summary-mode=disabled.
--summary-mode=legacy #5730The 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.
options.ext.loadimpact support #5774The 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",
},
};
k6/experimental/redis module #5485The 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.
ExporterType option from OpenTelemetry output #5754The 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.
SingleCounterForRate option from OpenTelemetry output #5830The 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.
K6_BINARY_PROVISIONING environment variable #5734The 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.
K6_ENABLE_COMMUNITY_EXTENSIONS environment variable #5733The 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.
k6 cloud commands #5833Providing 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 .
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.
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.
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.
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.js
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.
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.
http.get() or http.head() receive extra arguments that are silently ignored, helping catch common scripting mistakes. Thanks, @moko-poi!newAction-based Locator APIs in the browser module, improving reliability of browser tests. Thanks, @janHildebrandt98!k6 x docs hint to the main k6 help output for built-in documentation discovery. Thanks, @Reranko05!k6 x explore hint to the main k6 help output for extension discovery.v0.0.0+sha or v0.0.0-timestamp-sha), even when the running binary already satisfied the constraint.k6 cloud run TUI 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.k6 cloud run --local-execution ignoring K6_CLOUD_PUSH_REF_ID and unconditionally creating a new test run instead of reusing the provided run ID. Thanks, @Reranko05!bufferedAmount not being incremented when sending TypedArrays, causing it to go negative. Thanks, @prakharbirla-ng!handleExitEvent where Done() was signalled before the subscription was removed, causing tests to hang until the timeout.TaskQueue from the external github.com/mstoykov/k6-taskqueue-lib into internal/js/taskqueue, eliminating an awkward reverse dependency where the library's own tests depended on k6.internal/dashboard, making the web dashboard a built-in part of the k6 binary without requiring a separate extension. The dashboard is available via k6 run --out=web-dashboard.synctest package within lib/executor, eventloop, and timer tests for virtualized time, improving test determinism.go.opentelemetry.io/otel/exporters/otlp/otlptracehttp and otlpmetrichttp to v1.43.0 [security], adding a 4 MiB response body cap to mitigate memory exhaustion from misconfigured or malicious servers.go.opentelemetry.io/otel packages.github.com/grafana/sobek digest.github.com/grafana/k6-cloud-openapi-client-go.github.com/mailru/easyjson to v0.9.2.github.com/evanw/esbuild to v0.28.0.buf.build/gen/go/prometheus protobuf.github.com/andybalholm/brotli to v1.2.1.examples/ dependencies.github.com/fatih/color to v1.19.0.github.com/puerkitobio/goquery to v1.12.0.github.com/mattn/go-isatty to v0.0.21.v1.25.9.github.com/grafana/k6provider to v0.4.0.crazy-max/ghaction-chocolatey to v4.actions/setup-go to 4a36011.anchore/sbom-action to v0.24.0.github/codeql-action to v4.35.2.docker/login-action to v4.1.0.grafana/shared-workflows actions.actions/upload-artifact.v1.26.2).Connection: close response.github.com/klauspost/compress to v1.18.5.golang.org/x packages.v3.23.4.A huge thank you to the external contributors who helped during this release: @moko-poi, @janHildebrandt98, @Reranko05, @prakharbirla-ng, and @chrismooreproductions! 🙏