Open source

Version 2.2.0 release notes

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. Use the new --no-cloud-logs flag to opt out of streaming logs when working with --local-execution:

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

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

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

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

console
$ 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!

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

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

Two new experimental feature 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. 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!
shell
k6 run --features merge-run-tags,freeze-env script.js

For a full list of changes, including UX improvements and bug fixes, refer to the full release notes.