Version 2.2.0 release notes
k6 v2.2.0 is here 🎉! This release includes:
k6 cloud run --local-executionnow 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.TextEncoderandTextDecoderavailable as globals, andWritableStreamsupport ink6/experimental/streams.- A
k6 cloud load-zone listcommand. - Two new experimental feature flags:
merge-run-tagsandfreeze-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:
k6 cloud run --local-execution script.js
k6 cloud run --local-execution --no-cloud-logs script.jsConnect 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.
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 yesConfigurable 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 feature flags join the feature-flag system introduced in v2.1.0:
- #5714
merge-run-tagsmerges run tags per key across config layers, sooptions.tagsin a script is no longer silently discarded when--tagorK6_TAGSis also used. Thanks, @yordis! - #6032
freeze-envfreezes the__ENVobject, so modifications from script code throw aTypeError(in strict mode) instead of silently persisting across iterations and scenarios. Thanks, @lohitkolluri!
k6 run --features merge-run-tags,freeze-env script.jsFor a full list of changes, including UX improvements and bug fixes, refer to the full release notes.

