Skip to content

Releases: grafana/k6

v1.8.1

Choose a tag to compare

@github-actions github-actions released this 12 Aug 14:56
73b044f

k6 v1.8.1 is here! This patch release includes:

  • Bug fix for the cloud secret source being enabled by default, which broke scripts that configure their own secret source
  • Bug fix for HTTP/2 negotiation and error classification under Go 1.27
  • Security updates for gRPC, golang.org/x/net, golang.org/x/text, golang.org/x/crypto, OpenTelemetry, klauspost/compress, and the Go toolchain

Bug fixes

  • #6274 Stops enabling the Grafana Cloud secret source by default in k6 cloud run --local-execution, reverting #5875. Scripts that configured their own secret source failed with no secret source with name "default" is configured. Explicitly configured secret sources now work again as they did in v1.7. Fixes #6093.
  • #6275 Fixes HTTP/2 negotiation and error classification under Go 1.27, which changed HTTP/2 negotiation and error behaviour. Keeps VUs on HTTP/2, classifies connection and GOAWAY errors consistently across Go versions, and preserves unknown HTTP/2 error buckets. Backport of #6234.

Maintenance and security updates

  • #6193, #6194 Updates google.golang.org/grpc to v1.82.1 [security].
  • #6187, #6189 Updates golang.org/x/net to v0.56.0 [security].
  • #6188, #6190 Updates golang.org/x/text to v0.39.0 [security].
  • #6207 Updates go.opentelemetry.io/otel to v1.44.0 [security].
  • #6220 Updates github.com/klauspost/compress to v1.18.7 [security].
  • #6135 Updates the Go toolchain to v1.25.12 [security].
  • Updates golang.org/x/crypto to v0.53.0 [security].

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 10 Aug 14:01
00a9a1b

k6 v2.2.0 is here 🎉! This release includes:

  • k6 cloud run --local-execution now streams k6's logs to Grafana Cloud, so the test run's log view works for local execution too.
  • chromium.connectOverCDP(), which connects browser tests to an already-running Chromium instance.
  • TextEncoder and TextDecoder available as globals, and WritableStream support in k6/experimental/streams.
  • A k6 cloud load-zone list command.
  • Two new experimental feature flags: merge-run-tags and freeze-env.

Breaking changes

There are no breaking changes in this release.

New features

k6 cloud run --local-execution streams logs to Grafana Cloud #6171

When a cloud test runs locally with k6 cloud run --local-execution, k6's logs now stream to the Grafana Cloud test run, so the run's log view is populated the same way it is for cloud execution. Previously, local-execution logs stayed on the machine running k6 and never reached the cloud. Work with Grafana's secrets management to safely work with secrets and redact them if they're accidentally leaked into logs are pushed. Use the new --no-cloud-logs flag opts out to opt out of streaming of logs when working with --local-execution:

k6 cloud run --local-execution script.js
k6 cloud run --local-execution --no-cloud-logs script.js

Connect to a running browser with chromium.connectOverCDP() #6165

The browser module can now attach to an existing Chromium-based browser over the Chrome DevTools Protocol, mirroring Playwright's browserType.connectOverCDP(). Pass the browser's WebSocket endpoint and k6 manages the returned browser's connection — it's auto-closed at the end of the iteration, though you can call close() earlier to release the connection on demand.

import { chromium } from 'k6/browser';

export default async function () {
  const browser = await chromium.connectOverCDP('ws://localhost:9222/devtools/browser/<id>');
  const page = await browser.newPage();

  try {
    await page.goto('https://quickpizza.grafana.com/');
  } finally {
    await page.close();
    await browser.close();
  }
}

Unlike the K6_BROWSER_WS_URL environment variable, the endpoint is a runtime value — you can, for example, request a fresh session URL from a browser provider's API in setup() and connect to it from the iterations.

TextEncoder and TextDecoder globals #6182

TextEncoder and TextDecoder are now available as standard globals in both the init and VU contexts, no import required — matching how they are exposed in browsers and other JavaScript runtimes.

const encoded = new TextEncoder().encode('Hello, world!');
const decoded = new TextDecoder().decode(encoded);

WritableStream in k6/experimental/streams #6132

The experimental streams module now implements WritableStream and WritableStreamDefaultWriter following the WHATWG Streams specification, complementing the existing ReadableStream and paving the way for a future TransformStream implementation.

import { WritableStream } from 'k6/experimental/streams';

export default async function () {
  const stream = new WritableStream({
    write(chunk) {
      console.log(`wrote ${chunk}`);
    },
  });

  const writer = stream.getWriter();
  await writer.write('hello');
  await writer.close();
}

k6 cloud load-zone list command #6142

A new k6 cloud load-zone list subcommand lists the load zones — public and private — available in the configured Grafana Cloud k6 stack, mirroring the existing k6 cloud project list command. Output defaults to a human-readable table; pass --json to emit a JSON array instead.

$ k6 cloud load-zone list
Load zones for https://example.grafana.net:

ID                     NAME                     TYPE      AVAILABLE
amazon:us:ashburn      Ashburn, US (Amazon)     public    yes
amazon:sa:cape town    Cape Town, SA (Amazon)   public    yes

Configurable handleSummary() timeout #5854

The time budget for the handleSummary() callback — previously hardcoded to 120 seconds — is now configurable through the handleSummaryTimeout option or the K6_HANDLE_SUMMARY_TIMEOUT environment variable, so long-running tests with heavy summaries no longer fail with handleSummary() execution timed out. Thanks, @LBaronceli!

export const options = {
  handleSummaryTimeout: '5m',
};

New experimental feature flags: merge-run-tags and freeze-env

Two new experimental flags join the feature-flag system introduced in v2.1.0:

  • #5714 merge-run-tags merges run tags per key across config layers, so options.tags in a script is no longer silently discarded when --tag or K6_TAGS is also used — higher-priority layers win on conflicting keys instead of replacing the whole map. Thanks, @yordis!
  • #6032 freeze-env freezes the __ENV object, so modifications from script code throw a TypeError (in strict mode) instead of silently persisting across iterations and scenarios. Thanks, @lohitkolluri!
k6 run --features merge-run-tags,freeze-env script.js

UX improvements and enhancements

  • #5631 Makes the browser module's header accessors — response.allHeaders(), headerValue(), headerValues(), and headersArray() — return the raw wire headers (including Set-Cookie and security-related headers), correctly paired with each hop of a redirect chain instead of Chrome's provisional headers. As part of this, headerValues() now matches header names case-insensitively and splits repeated values on newlines rather than commas, and the browser_data_sent/browser_data_received metrics now include the raw header bytes and no longer vary run-to-run with CDP event ordering.
  • #6208 Makes k6 cloud reject the run flags (for example, --vus) with an unknown flag error and a non-zero exit code. Previously k6 cloud --vus 10 script.js accepted the flags, printed the help text, and exited 0 — running tests with k6 cloud directly was deprecated in v2.0.0 in favor of k6 cloud run.
  • #6096 Points the cloud secrets error at K6_CLOUD_SECRETS_TOKEN and K6_CLOUD_SECRETS_ENDPOINT when a test run is reused via K6_CLOUD_PUSH_REF_ID under --local-execution, instead of suggesting the --local-execution flag the user is already using.
  • #6196 Adds catch blocks to the browser examples so a failing iteration reports the original error instead of a subsequent page.close() failure. Thanks, @locker95!

Bug fixes

  • #6234 Classifies HTTP/2 errors by message so the error_code metric tag stays correct when k6 is built with Go 1.27 (whose x/net/http2 delegates to the standard library), and explicitly enables HTTP/2 negotiation on VU transports.
  • #6232 Drains queued log entries in the Loki hook at shutdown so --out loki and cloud log streaming no longer lose the final batch, and emits a k6 dropped N log messages warning when the cloud log buffer overflows instead of dropping logs silently.
  • #6125 Serializes the first concurrent open of a file in the caching filesystem so parallel fs.open() calls on the same file no longer read zero or truncated bytes.
  • #6147 Fixes a data race and inconsistent request-interception state when browser routes are added or removed concurrently. Thanks, @somak2kai!
  • #6070 Flushes buffered file log output once per second so recent logs aren't lost when k6 is killed before shutdown. Thanks, @rohan-patnaik!
  • #6205 Stops sending an invalid Sec-WebSocket-Protocol header when tailing Grafana Cloud logs; spec-strict servers rejected the handshake with websocket: bad handshake.
  • #6200 Leaves a counter's rate unset when the observed duration is zero, instead of computing +Inf and spuriously failing rate thresholds. Thanks, @samarth70!
  • #6195 Initializes a gauge's maximum from the first sample so all-negative gauge series no longer report max=0. Thanks, @Solaris-star!
  • #6145 Prevents the OpenTelemetry output from panicking at startup when basic auth is configured without K6_OTEL_HEADERS. Thanks, @lukdz!
  • #6140 Stops SharedArray deep-freezing JS primitives, which needlessly wrapped large strings in String objects — cutting memory usage in the reported reproduction from roughly 1 GB to 100 MB.

Maintenance and internal improvements

  • #6126, #6224, #6229 Adds anonymous extension usage to the k6 usage report: a run reports the Go module path, version, and type of registry-cataloged extensions it actually uses (imported k6/x/ modules, output extensions selected with --out, and k6 x subcommands). Private and unlisted extensions are never reported, and the existing --no-usage-report opt-out covers it.
  • #6183, #6218 Updates Sobek and regexp2, making WeakMap/WeakSet entries garbage-collectable, improving string and typed-array correctness and performance, and bo...
Read more

v2.1.0

Choose a tag to compare

@github-actions github-actions released this 30 Jun 08:56
83a87a4

k6 v2.1.0 is here 🎉

This release includes:

  • An opt-in feature-flag system — --features, the K6_FEATURES environment variable, and a k6 features discovery command — shipping with experimental native histograms for trend metrics as its first flag.
  • A context-level proxy option for browser contexts.
  • Subcommand discovery in k6 x, so binaries can report which extension commands they expose.

Breaking changes

There are no breaking changes in this release.

New features

k6 cloud test list command #6007

A new k6 cloud test command group has been added, with a k6 cloud test list subcommand that lists the load tests of a Grafana Cloud k6 project. It complements the k6 cloud project list command introduced in v2.0.0.

The project to list tests for is resolved in the following order:

  1. The --project-id flag.
  2. The K6_CLOUD_PROJECT_ID environment variable (cloud config projectID).
  3. The default project of the configured stack, populated by k6 cloud login.

Output defaults to a human-readable table. Pass --json to emit a JSON array instead, mirroring the format established by k6 cloud project list.

k6 cloud test list
k6 cloud test list --project-id 12345
k6 cloud test list --json

Feature flags and experimental native histograms #6055, #6056

k6 now has an opt-in feature-flag mechanism for trialing new, not-yet-stable behavior without affecting existing runs. Flags can be enabled on k6 run and k6 cloud run through the --features flag (comma-separated or repeated), the K6_FEATURES environment variable, or the features key in config.json. Enabled flags are surfaced as metric tags and propagated into archives and cloud workers so a run behaves consistently wherever it executes.

Use k6 features (or k6 features --json) to discover the available flags and their lifecycle:

$ k6 features
FEATURE             LIFECYCLE      DESCRIPTION
native-histograms   Experimental   Use native histograms for trend metrics

The first flag shipped is native-histograms, an experimental flag that makes k6 use native histograms for trend metrics:

k6 run --features native-histograms script.js
# or
K6_FEATURES=native-histograms k6 run script.js

Subcommand discovery in k6 x #5972

Running k6 x now lists the available subcommands — both the ones baked into the binary and those advertised by the extension registry (official and community). Tab-completion surfaces the same set once the catalog has been cached locally by a prior k6 x run, so completion never blocks on the network.

$ k6 x
...
Available Commands:
  agent       Bootstrap an AI-assisted k6 testing workflow in any editor
  docs        CLI k6 docs for AI agents and users
  explore     Explore k6 extensions for Automatic Resolution
  mcp         An MCP server for k6 for AI agents

This makes a k6 binary self-describing — particularly useful for AI agents driving k6, which previously had no way to introspect which extension subcommands were available.

Browser context proxy option #5924

Browser contexts can now be configured with a context-level proxy option, letting you route a context's traffic through a proxy without launching a custom-built binary or relying on environment proxy variables (which only affected k6's DevTools WebSocket connection). The option is wired to Chromium through Target.createBrowserContext, and invalid proxy configuration now fails early when proxy.server is missing. Thanks, @nightt5879!

const context = await browser.newContext({
  proxy: {
    server: 'http://proxy.test:8080',
    bypass: 'localhost,127.0.0.1',
  },
});

Browser locator.isInViewport() #6023

A new locator.isInViewport() method reports whether an element intersects the browser viewport. It accepts an optional ratio (0 to 1) that sets how much of the element must be visible, defaulting to 0 so any visible pixel counts, matching Playwright's toBeInViewport semantics. The call waits for the element to attach, honoring the timeout option, then measures the intersection once. Thanks, @Anuragp22!

const button = page.locator('button#submit');
if (await button.isInViewport()) {
  await button.click();
}

Basic auth for the OpenTelemetry HTTP exporter #5997

The OpenTelemetry output's HTTP exporter can now send HTTP Basic Auth credentials. Set them through the K6_OTEL_HTTP_EXPORTER_USERNAME and K6_OTEL_HTTP_EXPORTER_PASSWORD environment variables, or the username and password keys in the output config.

K6_OTEL_HTTP_EXPORTER_USERNAME=user \
K6_OTEL_HTTP_EXPORTER_PASSWORD=secret \
k6 run --out opentelemetry script.js

single() selection helper in k6/html #6002

Selection.single(selector) returns at most one matching element, backed by goquery's Single matcher for a faster lookup than find() when you only need the first match. Thanks, @rohan-patnaik!

import { parseHTML } from 'k6/html';

const doc = parseHTML(content);
const title = doc.single('h1').text();

UX improvements and enhancements

  • #5971 Tags browser API failures with module=browser so that browser errors surfaced in Grafana Cloud Logs can be filtered separately from other log sources.

Bug fixes

  • #5794 Makes the --vus flag work as a standalone execution shortcut instead of being silently ignored when a script defines scenarios. Running k6 run script.js --vus N now creates a shared-iterations scenario with N VUs and N iterations, overriding any script-defined scenarios with a warning — consistent with how --iterations, --duration, and --stages already behave. Thanks, @Reranko05!
  • #6013 Rejects invalid threshold percentiles. A percentile aggregation value outside the 0 to 100 range (or NaN) now fails parsing with a clear message instead of being silently accepted. Thanks, @immanuwell!
  • #6011 Writes the on-disk k6 config file with owner-only permissions (0o600, inside a 0o700 directory). The file can hold the Grafana Cloud API token (collectors.cloud.token), so tightening it keeps other local users on shared hosts (CI runners, multi-user boxes, sidecar containers) from reading the token. Existing configs are upgraded on the next write, for example the next k6 cloud login.

Maintenance and internal improvements

  • #6033 Moves Docker Hub image publishing to a Google Artifact Registry mirror.
  • #5953 Installs s3cmd via apt instead of pip to fix the k6packager image build.
  • #6052 Fixes the browser end-to-end test workflow.
  • #5984 Routes per-test logger output to the test instance instead of the global logrus, improving test isolation.
  • #5985 Fixes the flaky TestPageScreenshotFullpage browser test.
  • #5981 Lets Renovate track the Go minor version in the setup-go workflows.
  • #5968 Honors the caller-pinned ref in the shared lint action.
  • #6041, #6054 Aligns the Go module directive and toolchain (1.25.0 / 1.25.11).
  • #5967 Updates the release notes template after v2.0.0.
  • #6015 Updates golang.org/x/net to v0.55.0 [security].
  • #6026 Updates golang.org/x/crypto to v0.52.0 [security].
  • #5962, #6028 Updates google.golang.org/grpc to v1.81.1.
  • #5960 Updates grafana/shared-workflows/get-vault-secrets to v1.3.2.
  • #5958 Updates grafana/shared-workflows/azure-trusted-signing to v1.0.2.
  • #5957 Updates github/codeql-action to v4.35.4.
  • #5959 Updates grafana/shared-workflows/dockerhub-login to v1.0.4.
  • #6009 Moves the browser PageScreenshotOptions parsing into the mapping layer.
  • #5964 Adds the k6 feature-flags specification under openspec/.
  • #6067 Forces the legacy x/net/http2 implementation on the gotip CI test job.
  • #6065 Lets Renovate update the Dockerfile on the v1.x branch.
  • #6031 Updates go.opentelemetry.io/otel to v1.44.0.
  • #6086 Updates golang.org/x dependencies (crypto to v0.53.0, net to v0.56.0, term to v0.44.0).
  • #6061 Updates golang.org/x/sync to v0.21.0.
  • #6030 Updates github.com/tidwall/gjson to v1.19.0.
  • #6029 Updates github.com/mccutchen/go-httpbin/v2 to v2.23.0.
  • [#6063](https://gi...
Read more

v1.8.0

Choose a tag to compare

@github-actions github-actions released this 08 Jun 10:13

k6 v1.8.0 is here! This maintenance release on v1.x includes:

  • Cloud secrets are now automatically available in k6 cloud run --local-execution — use --no-cloud-secrets to opt out.
  • Pre-manifest extension dependencies are captured in archive metadata for cloud consumers.
  • Structured logging from k6provider for better visibility into automatic extension provisioning.
  • Multiple bug fixes for Browser, WebSocket, and Cloud modules.
  • Dependency updates and reliability improvements.

Breaking changes

There are no breaking changes in this release.

New features

Cloud secrets now automatically available in local execution #5738 & #5875

When running k6 cloud run --local-execution, secrets stored in Grafana Cloud are now automatically available to your script via secrets.get() without any additional configuration.

To opt out, pass --no-cloud-secrets:

k6 cloud run --local-execution --no-cloud-secrets script.js

Thanks, @vortegatorres!

Pre-manifest extension dependencies captured in archive metadata #5819 & #5977

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 & #5993 Warns when http.get() or http.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!
  • #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.

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+sha or v0.0.0-timestamp-sha), even when the running binary already satisfied the constraint.
  • #5574 Fixes position parser for base pointer options. Thanks, @chrismooreproductions!
  • #5630 & #5987 Fixes duplicate redirect request metric emissions in the browser module, where each redirect was incorrectly emitting metrics for all prior redirects in the chain.
  • #5620 & #5991 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!
  • #5716 & #5990 Fixes WebSocket bufferedAmount not being incremented when sending TypedArrays, causing it to go negative. Thanks, @prakharbirla-ng!
  • #5814 & #5975 Fixes 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!
  • #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 handleExitEvent where Done() was signalled before the subscription was removed, causing tests to hang until the timeout.
  • #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.
  • #5923 & #5989 Fixes a nil pointer panic in ElementHandle.DefaultTimeout (and any method that calls it, such as GetAttribute) when invoked on a nil or partially-initialized handle. Thanks, @SAY-5!

Maintenance and internal improvements

  • #5896 & #5897 Updates 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.
  • #5857, #5950 Updates Go to v1.25.10.
  • #5946 Updates golang.org/x/net to v0.55.0 [security].
  • #6042 Updates Go toolchain to v1.25.11 [security].
  • #6047 Updates golang.org/x/crypto to v0.52.0 [security].
  • #5863, #5880, #5908 Updates github.com/grafana/k6provider to v0.5.0.
  • #5740, #5796, #5910 Updates github.com/grafana/sobek digest.
  • #6035 Move Docker Hub publishing to GAR mirror.
  • #6064 Bumps Dockerfile images for security updates.

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! 🙏

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 11 May 09:27

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-controlled executor has been removed — scripts using executor: externally-controlled will no longer run.
  • Cloud run non-threshold aborts (aborted by user, system, timeout, etc.) now return exit code 97 instead of 0.
  • options.ext.loadimpact is no longer supported — use options.cloud.
  • k6/experimental/redis module has been removed.
  • The k6 cloud script.js positional form has been fully removed — use k6 cloud run script.js.
  • A stack is now required for all k6 cloud commands — 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 --address to enable it.
  • (new since v2.0.0-rc1) New k6 cloud project list command 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-secrets to 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 pause
  • k6 resume
  • k6 scale
  • k6 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 cloudk6 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 r...

Read more

v2.0.0-rc1

v2.0.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 Apr 10:05

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:

  • 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-controlled executor has been removed — scripts using executor: externally-controlled will no longer run.
  • Cloud run non-threshold aborts (aborted by user, system, timeout, etc.) now return exit code 97 instead of 0.
  • options.ext.loadimpact is no longer supported — use options.cloud.
  • k6/experimental/redis module has been removed.
  • The k6 cloud command now shows help by default instead of attempting to run.
  • A stack is now required for all k6 cloud commands — 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.

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"

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.

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 pause
  • k6 resume
  • k6 scale
  • k6 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 cloudk6 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.

k6 cloud script.js no longer runs a test #5624

Running 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.

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

Pre...

Read more

v1.7.1

Choose a tag to compare

@github-actions github-actions released this 30 Mar 10:54
9f82e6f

k6 v1.7.1 is here 🎉! This release includes:

  • Dependency updates for google.golang.org/grpc.

Maintenance and internal improvements

v1.7.0

Choose a tag to compare

@github-actions github-actions released this 25 Mar 10:10
776c078

k6 v1.7.0 is here 🎉! This release includes:

  • Automatic resolution for subcommand extensions — no more manual xk6 builds required to use them!
  • K6_SECRET_SOURCE env var as an alternative to --secret-source, accepting the same syntax.

Breaking changes

There are no breaking changes in this release.

New features

Automatic resolution for subcommand extensions #5664

You can now rely on automatic extension resolution
also when using a subcommand extension
that isn't included in the current binary.

Previously, using extension subcommands required manually building a custom k6 binary with xk6. Now, k6 detects the
missing extension, provisions the binary on demand, and executes the command transparently — the same experience already
available for JavaScript extensions.

For instance, if you run:

k6 x httpbin

and the xk6-subcommand-httpbin subcommand extension isn't in the
current binary, k6 will automatically provision a binary with it on demand and execute the command transparently.

UX improvements and enhancements

  • #5655 Recommends the OpenTelemetry output instead of InfluxDB.
  • #5724 Adds K6_SECRET_SOURCE env var as an alternative to --secret-source, accepting the same syntax. Thanks @vortegatorres, for the contribution!

Bug fixes

  • #5629 Ensures that all redirected requests are handled for page.on('response') and page.on('requestfinished').

Maintenance and internal improvements

  • #5447 Updates the actions/setup-go action to 7a3fe6c.
  • #5471 Uses WPT's harness to test the WebCrypto API. Thanks @bjchris32, for the contribution!
  • #5583, #5687 Move Size and PageEmulateMediaOptions option parsing to the Browser's mapping layer. Thanks @baeseokjae, for the contribution!
  • #5598 Updates the anchore/sbom-action action to v0.22.2.
  • #5599 Updates github.com/klauspost/compress to v1.18.4.
  • #5600 Updates the docker/login-action action to v3.7.0.
  • #5610 Improves error wrapping for Browser's actionability functions. Thanks @joaquinalmora, for the contribution!
  • #5612 Adds a AGENTS.md for guiding coding agents.
  • #5615 Updates the actions/checkout action to de0fac2.
  • #5618 Updates protoreflect to v1.18.0.
  • #5619 Updates google.golang.org/grpc to v1.78.0.
  • #5626 Uses cmd/state constants when possible.
  • #5643, #5647 Fix goroutine leak when running the browser tests.
  • #5646 Update the Go toolchain version to 1.24.13.
  • #5654, #5666 Update the tag of the Docker image for Go.
  • #5656 Fixes browser tests teardown races.
  • #5660 Trims away the use of afero outside of the fsext module.
  • #5678 Updates golangci-lint to 2.10.1.
  • #5688 Updates go.opentelemetry.io/otel/sdk to v1.40.0.
  • #5689 Fixes browser tests by increasing the CI test run timeout.
  • #5691 Updates the actions/stale action to b5d41d4.
  • #5692 Updates the grafana/shared-workflows/get-vault-secrets action to v1.3.1.
  • #5695 Updates the github/codeql-action action to v4.32.4.
  • #5702 Bumps the Go min version to 1.25 and default to 1.26, and fixes lint issues enabled by the new minimum.
  • #5708 Bumps TC39 tests.
  • #5728 Updates xk6-dashboard to v0.8.1.
  • #5735 Excludes non-essential administrative and metadata files from the vendor directory.

Roadmap

k6 v2.0.0 is the next planned release. It will include a set of breaking changes that have been discussed and planned.
You can find the list of planned breaking changes in #5062.

v1.6.1

Choose a tag to compare

@github-actions github-actions released this 16 Feb 10:52
2ac2bb5

k6 v1.6.1 is here! This patch release includes:

  • Bug fix for a race condition in the experimental CSV module
  • Bug fix for manifest k6 version override
  • Version updates for Go toolchain and Docker images

Bug fixes

  • #5632 Fixes a race condition in the experimental/csv module when multiple files with async code use csv.parse in parallel during initialization.
  • #5642 Fixes an issue where k6 was not always added as a build dependency, preventing manifests from overriding the k6 version.

Maintenance and security updates

  • #5641 Adds chromium as an explicit dependency for with-browser Docker image.
  • #5646 Updates Go toolchain version to 1.24.13.
  • #5654 Updates the used Go version in the Docker image to v1.25.7.

v1.6.0

Choose a tag to compare

@github-actions github-actions released this 10 Feb 09:12
d97957f

k6 v1.6.0 is here 🎉! This release includes:

  • Cloud commands now support configurable default Grafana Cloud stack.
  • New k6 deps command for analyzing script dependencies.
  • Browser APIs enhancements with frameLocator(), goBack(), goForward() methods.
  • Crypto module adds PBKDF2 support for password-based key derivation.
  • jslib gets a new TOTP library for time-based one-time password generation and validation.
  • New mcp-k6 MCP server for AI-assisted k6 script writing.

Breaking changes

There are no breaking changes in this release.

New features

Configurable default stack for Cloud commands #5420

Cloud commands now support configuring the default Grafana Cloud stack you want to use. The stack slug (or stack id) is used by the Cloud to determine which default project to use when not explicitly provided.

Previously, users had to specify the project id for every test run. With this change, you can configure a default stack during login, and k6 will use it to automatically resolve the appropriate default project. This is particularly useful for organizations with multiple Grafana Cloud stacks or when working across different teams and environments.

Users can also set up a specific stack for every test run, either using the new option stackID or the environment variable K6_CLOUD_STACK_ID.

Please note that, in k6 v2, this stack information will become mandatory to run a test.

# Login interactively and select default stack
k6 cloud login

# Login and set default stack with token
k6 cloud login --token $MY_TOKEN --stack my-stack-slug

# Run test using the configured default stack
k6 cloud run script.js

# Run test using a specific stack
K6_CLOUD_STACK_ID=12345 k6 cloud run script.js

# Stack id can also be set in the options
export const options = {
  cloud: {
    stackID: 123,
    projectID: 789,  // If the project does not belong to the stack, this will throw an error
  },
};

This simplifies the cloud testing workflow and prepares k6 for upcoming changes to the Grafana Cloud k6 authentication process, where the stack will eventually become mandatory.

k6 deps command and manifest support #5410, #5427

A new k6 deps command is now available to analyze and list all dependencies of a given script or archive. This is particularly useful for understanding which extensions are required to run a script, especially when using auto extension resolution.

The command identifies all imports in your script and lists dependencies that might be needed for building a new binary with auto extension resolution. Like auto extension resolution itself, this only accounts for imports, not dynamic require() calls.

# Analyze script dependencies
k6 deps script.js

# Output in JSON format for programmatic consumption
k6 deps --json script.js

# Analyze archived test dependencies
k6 deps archive.tar

This makes it easier to understand extension requirements, share scripts with clear dependency information, and integrate k6 into automated build pipelines.

In addition, k6 now supports a manifest that specifies default version constraints for dependencies when no version is defined in the script using pragmas. If a dependency is imported without an explicit version, it defaults to "*", and the manifest can be used to replace that with a concrete version constraint.

The manifest is set through an environment variable as JSON with keys being a dependency and values being constraints:

K6_DEPENDENCIES_MANIFEST='{"k6/x/faker": ">=v0.4.4"}' k6 run scripts.js

In this example, if the script only imports k6/x/faker and does not use a use k6 with k6/x/faker ... directive, it will set the version constraint to >=v0.4.4. It will not make any changes if k6/x/faker is not a dependency of the script at all.

Browser module: frameLocator() method #5487

The browser module now supports frameLocator() on Page, Frame, Locator, and FrameLocator objects. This method creates a locator for working with iframe elements without the need to explicitly switch contexts, making it much easier to interact with embedded content.

Frame locators are particularly valuable when testing applications with nested iframes, as they allow you to chain locators naturally while maintaining readability:

Click to expand example code
import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
};

export default async function () {
  const page = await browser.newPage();

  try {
    await page.goto('https://example.com');

    // Locate an iframe and interact with elements inside it
    const frame = page.frameLocator('#payment-iframe');
    await frame.locator('#card-number').fill('4242424242424242');
    await frame.locator('#submit-button').click();

    // Chain frame locators for nested iframes
    const nestedFrame = page
      .frameLocator('#outer-frame')
      .frameLocator('#inner-frame');
    await nestedFrame.locator('#nested-content').click();
  } finally {
    await page.close();
  }
}

This complements existing frame handling methods and provides a more intuitive API for working with iframe-heavy applications.

Browser module: goBack() and goForward() navigation methods #5494

The browser module now supports page.goBack() and page.goForward() methods for browser history navigation. These methods allow you to navigate the page's history, similar to clicking the browser's back/forward buttons.

Click to expand example code
import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
};

export default async function () {
  const page = await browser.newPage();

  try {
    await page.goto('https://example.com');
    await page.goto('https://example.com/page2');
    
    // Navigate back to the previous page
    await page.goBack();
    
    // Navigate forward again
    await page.goForward();
    
    // Both methods support optional timeout and waitUntil parameters
    await page.goBack({ waitUntil: 'networkidle' });
  } finally {
    await page.close();
  }
}

Browser module: Request event handlers #5481, #5486

The browser module now supports page.on('requestfailed') and page.on('requestfinished') event handlers, enabling better monitoring and debugging of network activity during browser tests.

The requestfailed event fires when a request fails (network errors, aborts, etc.), while requestfinished fires when a request completes successfully.

Click to expand example code
import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
};

export default async function () {
  const page = await browser.newPage();

  // Monitor failed requests
  page.on('requestfailed', (request) => {
    console.log(`Request failed: ${request.url()}`);
  });

  // Monitor successful requests
  page.on('requestfinished', (request) => {
    console.log(`Request finished: ${request.url()}`);
  });

  await page.goto('https://example.com');
  await page.close();
}

These event handlers provide deeper insights into network behavior during browser testing and help identify issues that might not be immediately visible.

Crypto module: PBKDF2 support #5380

The crypto module now supports PBKDF2 for deriving cryptographic keys from passwords. PBKDF2 is widely used for password hashing and key derivation in security-sensitive applications, and this addition enables testing of systems that use PBKDF2 for authentication or encryption.

For usage examples, check out the one provided in the repository or refer to the documentation.

WebSockets module is now stable #5586

The websockets module has been promoted to stable status and is now available via the k6/websockets path.
The experimental k6/experimental/websockets module will be removed in a future release. Users should migrate to the stable k6/websockets module.

To migrate, simply update your import statement:

// Old (experimental)
import ws from 'k6/experimental/websockets';

// New (stable)
import ws from 'k6/websockets';

No other changes are required because the API is the same.

Console logging: ArrayBuffer and TypedArray support #5496

console.log() now properly displays ArrayBuffer and TypedArray objects, making it easier to debug binary data handling in your test scripts. Previously, these types would not display useful information, making debugging difficult when working with binary protocols, file uploads, or WebS...

Read more