k6 v0.39.0 is here! :tada: It's a small release that includes a bunch of bugfixes and minor enhancements. Much of our focus was on some upcoming big changes. You can read about what's coming up next in the [Roadmap and future plans section](#roadmap-and-future-plans).

## Enhancements and UX improvements

- [#2274](https://github.com/grafana/k6/pull/2274) and [#2560](https://github.com/grafana/k6/pull/2560) improved the `csv` output with support for a new `timeFormat` option. The possible values are `unix` (default) and `rfc3399`. You can also configure it through the `K6_CSV_TIME_FORMAT` environment variable. Thanks, @rpocklin!
- [#2509](https://github.com/grafana/k6/pull/2509) added the `clear()` and `delete()` methods to the [`CookieJar` object](https://k6.io/docs/javascript-api/k6-http/cookiejar/) from the [`k6/http`](https://k6.io/docs/javascript-api/k6-http/) module. Thanks, @Maksimall89!
- [#2282](https://github.com/grafana/k6/pull/2282) increased the precision of the iteration-progress bar in the UI. Thanks, @m3hm3t and @DarkAEther!
- [#2568](https://github.com/grafana/k6/pull/2568) added more descriptive error messages when there were problems with parsing a config file.

## Bug fixes

- [#2523](https://github.com/grafana/k6/pull/2523) fixed a gRPC marshaling error when `any.proto` was used for a type. Thanks, @Flowersea!
- [#2534](https://github.com/grafana/k6/pull/2534) fixed the return type of [`Selection.map()`](https://k6.io/docs/javascript-api/k6-html/selection/selection-map) from the [`k6/html` module](https://k6.io/docs/javascript-api/k6-html/) to the correct object types instead of a forced array of strings.
- [#2502](https://github.com/grafana/k6/pull/2502) made it so k6 waits for scenario executors to fully finish before updating their final progress in the UI, preventing misleading red crosses ([#2500](https://github.com/grafana/k6/issues/2500)).
- [#2524](https://github.com/grafana/k6/pull/2524) fixed a bug where GoError string contained missing URL values ([#2537](https://github.com/grafana/k6/issues/2537)).
- [#2530](https://github.com/grafana/k6/pull/2530) fixed a wrong error message on remote resolution.
- [#2542](https://github.com/grafana/k6/pull/2542) fixed a bug where `Rate` metric and sub-metric values were shown as `NaN` in the end-of-test summary if there were no measured values for them during the test run.
- [#2558](https://github.com/grafana/k6/pull/2558) fixed a panic when trying to set the value of a [`vu.tags` element from `k6/execution`](https://k6.io/docs/javascript-api/k6-execution/#vu) to `null` or `undefined`.
- [#2567](https://github.com/grafana/k6/pull/2567) fixed a panic when trying to access some [`k6/execution`](https://k6.io/docs/javascript-api/k6-execution/) properties outside of a VU context, e.g. trying to access `execution.scenario` in `setup()`.

## Maintenance and internal improvements

- [#2550](https://github.com/grafana/k6/pull/2550) updated the used Go version to 1.18.
- [#2524](https://github.com/grafana/k6/pull/2524), [#2551](https://github.com/grafana/k6/pull/2551), [#2552](https://github.com/grafana/k6/pull/2552), [#2553](https://github.com/grafana/k6/pull/2553), [#2554](https://github.com/grafana/k6/pull/2554), [#2555](https://github.com/grafana/k6/pull/2555) updated various Go dependencies in k6.
- [#2583](https://github.com/grafana/k6/pull/2583) added a deprecation warning for thresholds that use the `url`, `error`, `vu` or `iter` tags, which [will become](#refactoring-metrics) un-indexable in the future.

# Roadmap and future plans

As the lack of big changes in this release suggests, we've focused the last few months' efforts on a few areas that haven't yet been merged into the core of k6.

In this section, we'd like to inform the community about important features that we're currently working on - our short-term roadmap in a sense. We'll also use it to give notice of breaking changes we plan to make in the near future.

## `k6/experimental/*` JS modules

Over the last several k6 releases, among a lot of other refactorings, we've added support for JavaScript event loops ([#2228](https://github.com/grafana/k6/pull/2228)) in k6 VUs and added a new Go API for exposing built-in and xk6 extension modules to user scripts ([announcement](https://github.com/grafana/k6/blob/master/release%20notes/v0.36.0.md#extensions), [docs](https://k6.io/docs/extensions/guides/create-an-extension/#advanced-javascript-extension)). This has given us (and any xk6-extension authors!) the ability to better support various asynchronous streaming/messaging/etc. protocols ([#882](https://github.com/grafana/k6/issues/882#issue-392218655)).

We've started building some of these newly possible APIs as [xk6 extensions](https://k6.io/docs/extensions/) first, to be able to iterate on them more quickly and get some user feedback while we are building them. [xk6-websockets](https://github.com/grafana/xk6-websockets), [xk6-timers](https://github.com/grafana/xk6-timers) and [xk6-redis](https://github.com/grafana/xk6-redis/) are some of the first such APIs, but we plan to also work on support for gRPC streaming ([#2020](https://github.com/grafana/k6/issues/2020)), messaging protocols ([#1269](https://github.com/grafana/k6/issues/1269)), a new and better HTTP API ([#2461](https://github.com/grafana/k6/issues/2461)) and many others in the future!

We want to eventually include a lot of these APIs in the k6 core as built-in modules that users can directly use, without needing to mess with xk6 or Go compilation. However, because we try to keep the built-in k6 APIs stable and backwards-compatible, we want to get more user feedback before we do that, while we are still free to iterate and make (hopefully minor) breaking changes.

So, we decided to create a new middle ground between the unstable and purely external xk6 extensions and the stable built-in k6 APIs―built-in `k6/experimental/*` modules! Our goal is that, starting with the next k6 v0.40.0 release, we'll start releasing some or all of these core-bound extensions as built-in k6 modules under these `k6/experimental/` import paths. This will let k6 users, both OSS and Cloud, to give us feedback and help us improve the APIs before we stabilize them.

As is hopefully clear from the name, our usual guarantees of API stability won't apply to these modules while they are still experimental. We reserve the right to make breaking changes in `experimental` modules, up to and including completely dropping them. We don't expect big breaking changes will need to happen often, but we want to be clear they aren't impossible. Finally, when an API has been stabilized and made available under a regular import path, we'll deprecate its experimental import path. To make the transition easier, both import paths will be available simultaneously for at least one k6 version.

## Native support for ECMAScript modules

At the moment, k6 has support for [ECMAScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (ESM, i.e. `import`, `export`, etc.) via [automatic transpilation](https://k6.io/docs/using-k6/javascript-compatibility-mode/) of scripts by the built-in [Babel.js](https://babeljs.io/). That mostly works, but it has caused some performance and compatibility problems ([#824](https://github.com/grafana/k6/issues/824#issuecomment-915918351) and [#2168](https://github.com/grafana/k6/issues/2168#issuecomment-1014276690) among others), so we want to support ESM modules and all other ES6 features directly in k6, without the need for Babel.js ([#2296](https://github.com/grafana/k6/issues/2296#issuecomment-993356717)). [goja](https://github.com/dop251/goja), the JavaScript runtime we use to evaluate k6 scripts, doesn't yet have native ESM support, so we are currently working on adding it there, to then be able to support ECMAScript modules natively in k6!

That work has been ongoing for a while and we're making progress, but it will likely not be ready in time for the next k6 v0.40.0 release. We are mentioning it here because we will probably need to make a few minor breaking changes and fixes of currently undefined behavior in k6 to support ESM modules natively.

For example, at the moment, some values like the consolidated script `options` were unintentionally made available globally, in all JS modules of a test, instead of just in the exported `options` value from the main JS module. That is not the intended or documented behavior, it's somewhere between a bug and undefined behavior, and we'll need to fix it ([#2571](https://github.com/grafana/k6/pull/2571)) and other similar issues like it, starting in k6 v0.40.0. We don't expect many scripts to break because of these fixes, but we'll nevertheless announce them in the release notes of the k6 version that they happen in.

## Refactoring metrics

Over the last several k6 releases, we've also slowly been refactoring and improving the metrics internals in k6 (see [#2071](https://github.com/grafana/k6/pull/2071), [#2330](https://github.com/grafana/k6/issues/2330), [#2426](https://github.com/grafana/k6/pull/2426), [#2463](https://github.com/grafana/k6/pull/2463), [#2433](https://github.com/grafana/k6/pull/2433), [#2442](https://github.com/grafana/k6/pull/2442), among others). This has already brought many side benefits and minor bugfixes, and we still have a lot of work left (e.g. [#1889](https://github.com/grafana/k6/issues/1889), [#572](https://github.com/grafana/k6/issues/572), [#2430](https://github.com/grafana/k6/issues/2430), [#1831](https://github.com/grafana/k6/issues/1831)), but we've finally reached the point where we can almost start implementing some major new features effectively!

One of the upcoming next big steps is the introduction of a "time series" concept internally in k6 ([#2580](https://github.com/grafana/k6/issues/2580)). We'll start to efficiently group samples (i.e. metric measurements) with the same metric and tags into a single `TimeSeries`, which would unlock many of possibilities that were previously too inefficient to implement.

Another upcoming metrics-related change would be the refactoring of [metric tags](https://k6.io/docs/using-k6/tags-and-groups/#tags) into two distinct types ([#2584](https://github.com/grafana/k6/issues/2584)) - ones that can be used for indexing (so, in the `TimeSeries` mentioned above, in [sub-metric thresholds](https://k6.io/docs/using-k6/thresholds/#thresholds-on-tags), in certain outputs that do aggregation based on tags, etc. ) and ones that cannot (e.g. high-cardinality metadata that's often unique for every data point).

Unfortunately, we'll need to make a few minor breaking changes. The current [`url`, `error`, `vu` and `iter` system tags](https://k6.io/docs/using-k6/tags-and-groups/#system-tags) will be made non-indexable by default, to reflect their usually very high cardinality, so they won't be usable in thresholds. Instead of `error`, the `error_code` tag should be used there. And instead of `url`, users should already use the `name` tag to avoid issues, see the [documentation about URL grouping](https://k6.io/docs/using-k6/http-requests/#url-grouping). k6 v0.39.0 still supports thresholds with these tags, it will just print a warning if they are used.

### Prometheus remote-write output

Because of these changes, we'll finally be able to refactor and improve the [Prometheus remote-write output extension](https://github.com/grafana/xk6-output-prometheus-remote/). Our goal is to make it more efficient, polish its rough edges, and merge it into the k6 core as a built-in output module in the near future.

### Tracing support

Another new feature these changes would unlock is support for distributed tracing ([#2128](https://github.com/grafana/k6/issues/2128)).

Because of the upcoming support for high-cardinality unindexable metric tags, we'll be able to safely attach things like the unique trace and span IDs to every metric measurement without negatively affecting other parts of k6.