<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Using k6 on Grafana Labs</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/</link><description>Recent content in Using k6 on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/k6/v2.3.x/using-k6/index.xml" rel="self" type="application/rss+xml"/><item><title>Analyze script dependencies</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/k6-deps-command/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/k6-deps-command/</guid><content><![CDATA[&lt;h1 id=&#34;k6-deps-command&#34;&gt;k6 deps command&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;k6 deps&lt;/code&gt; command analyzes your k6 test script and outputs information about the dependencies your script uses.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 deps [options] &amp;lt;script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;description&#34;&gt;Description&lt;/h2&gt;
&lt;p&gt;When you run &lt;code&gt;k6 deps&lt;/code&gt;, k6 analyzes your test script and its imports to identify k6 extensions (such as &lt;code&gt;k6/x/faker&lt;/code&gt;, &lt;code&gt;k6/x/redis&lt;/code&gt;) and k6 itself that your script uses.&lt;/p&gt;
&lt;p&gt;The command outputs dependency information in human-readable format by default, or JSON format with the &lt;code&gt;--json&lt;/code&gt; flag. You can use this information to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand what k6 extensions your script uses&lt;/li&gt;
&lt;li&gt;Share dependency information with your team&lt;/li&gt;
&lt;li&gt;Use it to know if you need a custom binary or if the current one can run the script&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The command, like 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/run/#use-automatic-extension-resolution&#34;&gt;automatic extension resolution&lt;/a&gt;, is only able to find dependencies using import/export syntax and &amp;ldquo;use&amp;rdquo; directives in already found files. It doesn&amp;rsquo;t follow potential &lt;code&gt;require&lt;/code&gt; calls.&lt;/p&gt;
&lt;p&gt;The command also takes into account any provided 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#dependency-manifest&#34;&gt;dependency manifest&lt;/a&gt; and applies it during &lt;code&gt;k6 run&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;options&#34;&gt;Options&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Option&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;--json&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Output dependency information in JSON format. Without this flag, the output is human-readable.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;h3 id=&#34;generate-dependency-information&#34;&gt;Generate dependency information&lt;/h3&gt;
&lt;p&gt;Analyze your test script and output dependency information:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 deps script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This outputs dependency information in human-readable format to stdout.&lt;/p&gt;
&lt;h3 id=&#34;generate-json-output&#34;&gt;Generate JSON output&lt;/h3&gt;
&lt;p&gt;Output the dependency information in JSON format:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 deps --json script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;output-format&#34;&gt;Output format&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;k6 deps&lt;/code&gt; command outputs dependency information in human-readable format by default. When using the &lt;code&gt;--json&lt;/code&gt; flag, the output is a JSON object.&lt;/p&gt;
&lt;h3 id=&#34;human-readable-output&#34;&gt;Human-readable output&lt;/h3&gt;
&lt;p&gt;The default human-readable output shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Dependencies:&lt;/strong&gt; Lists k6 extensions and k6 itself with version constraints (or &lt;code&gt;(none)&lt;/code&gt; if there are no build dependencies)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Imports:&lt;/strong&gt; Lists all imports including file paths and module names&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Build Required:&lt;/strong&gt; Indicates &lt;code&gt;yes&lt;/code&gt; or &lt;code&gt;no&lt;/code&gt; whether a custom build is required&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;Build Dependencies:
  k6: &amp;gt;1.2.0
  k6/x/faker: *

Imports:
  file:///path/to/script.js
  k6/execution
  k6/x/faker

Custom Build Required: yes&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;json-output&#34;&gt;JSON output&lt;/h3&gt;
&lt;p&gt;When using the &lt;code&gt;--json&lt;/code&gt; flag, the output is a JSON object with three fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;buildDependencies&lt;/code&gt;: An object mapping k6 extension names (or &lt;code&gt;k6&lt;/code&gt; itself) to version constraints&lt;/li&gt;
&lt;li&gt;&lt;code&gt;imports&lt;/code&gt;: An array of strings listing all imports&lt;/li&gt;
&lt;li&gt;&lt;code&gt;customBuildRequired&lt;/code&gt;: A boolean indicating whether a custom build is required&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;#34;buildDependencies&amp;#34;: {
    &amp;#34;k6&amp;#34;: &amp;#34;&amp;gt;1.2.0&amp;#34;,
    &amp;#34;k6/x/faker&amp;#34;: &amp;#34;*&amp;#34;
  },
  &amp;#34;imports&amp;#34;: [
    &amp;#34;file:///path/to/script.js&amp;#34;,
    &amp;#34;k6/execution&amp;#34;,
    &amp;#34;k6/x/faker&amp;#34;
  ],
  &amp;#34;customBuildRequired&amp;#34;: true
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="k6-deps-command">k6 deps command&lt;/h1>
&lt;p>The &lt;code>k6 deps&lt;/code> command analyzes your k6 test script and outputs information about the dependencies your script uses.&lt;/p>
&lt;h2 id="usage">Usage&lt;/h2>
&lt;div class="code-snippet ">&lt;div class="lang-toolbar">
&lt;span class="lang-toolbar__item lang-toolbar__item-active">Bash&lt;/span>
&lt;span class="code-clipboard">
&lt;button x-data="app_code_snippet()" x-init="init()" @click="copy()">
&lt;img class="code-clipboard__icon" src="/media/images/icons/icon-copy-small-2.svg" alt="Copy code to clipboard" width="14" height="13">
&lt;span>Copy&lt;/span>
&lt;/button>
&lt;/span>
&lt;div class="lang-toolbar__border">&lt;/div>
&lt;/div>&lt;div class="code-snippet ">
&lt;pre data-expanded="false">&lt;code class="language-bash">k6 deps [options] &amp;lt;script&amp;gt;&lt;/code>&lt;/pre>
&lt;/div>
&lt;/div>
&lt;h2 id="description">Description&lt;/h2>
&lt;p>When you run &lt;code>k6 deps&lt;/code>, k6 analyzes your test script and its imports to identify k6 extensions (such as &lt;code>k6/x/faker&lt;/code>, &lt;code>k6/x/redis&lt;/code>) and k6 itself that your script uses.&lt;/p></description></item><item><title>Run a k6 test script</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/run-k6-test-script/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/run-k6-test-script/</guid><content><![CDATA[&lt;h1 id=&#34;run-a-k6-test-script&#34;&gt;Run a k6 test script&lt;/h1&gt;
&lt;p&gt;There are several ways you can use the Grafana k6 command-line tool (CLI) to run a k6 performance test. In this page, you&amp;rsquo;ll learn how to use each method and how they differ from each other.&lt;/p&gt;
&lt;h2 id=&#34;before-you-begin&#34;&gt;Before you begin&lt;/h2&gt;
&lt;p&gt;To run a CLI test, you&amp;rsquo;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A machine with 
    &lt;a href=&#34;/docs/k6/v2.3.x/get-started/installation/&#34;&gt;k6 installed&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/test-authoring/create-test-script-using-the-cli/&#34;&gt;test file&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;run-a-test-on-your-local-machine&#34;&gt;Run a test on your local machine&lt;/h2&gt;
&lt;p&gt;Running tests locally is a great way to incrementally test your script as you write it. For example, you can make sure that your 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;checks&lt;/a&gt; and 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;thresholds&lt;/a&gt; are configured correctly before you run a test with more VUs in Grafana Cloud k6.&lt;/p&gt;
&lt;p&gt;To run a test locally, use the &lt;code&gt;k6 run&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;run-a-test-using-grafana-cloud-k6&#34;&gt;Run a test using Grafana Cloud k6&lt;/h2&gt;
&lt;p&gt;Grafana Cloud k6 is a performance testing application that&amp;rsquo;s part of Grafana Cloud, and it&amp;rsquo;s powered by k6 OSS. It allows you to leverage all of the Grafana k6 OSS capabilities while managing the infrastructure needed for scaling servers, running load tests from multiple locations, storing test results, and providing dashboards to detect performance errors and regressions.&lt;/p&gt;
&lt;p&gt;Grafana Cloud k6 makes it easier to visualize and compare test results by providing you with built-in dashboards, while also making it easier to share and collaborate on test data with other teams in your organization.&lt;/p&gt;
&lt;p&gt;To run a cloud test from the CLI, authenticate with &lt;code&gt;k6 cloud login&lt;/code&gt; — it will prompt you interactively for your API token and stack:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 cloud login&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For non-interactive environments such as CI/CD, pass the values directly:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 cloud login --token &amp;lt;API_TOKEN&amp;gt; --stack &amp;lt;STACK_SLUG&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the CLI authentication configured, you can run cloud tests by using the &lt;code&gt;k6 cloud&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 cloud run cloud_demo.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also run a test from a local machine and stream the results for storage and visualization on Grafana Cloud. A common use case for this feature is to run load tests in a CI/CD environment, or on networks that aren&amp;rsquo;t accessible from the public internet.&lt;/p&gt;
&lt;p&gt;To run a test locally and stream the results to Grafana Cloud k6, use the &lt;code&gt;k6 cloud run --local-execution&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 cloud run --local-execution cloud_demo.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The &lt;code&gt;k6 cloud run --local-execution&lt;/code&gt; command uploads the test archive k6 produces from your test script and resources to Grafana Cloud.&lt;/p&gt;
&lt;p&gt;You can change this behavior by adding the &lt;code&gt;--no-archive-upload&lt;/code&gt; option to your command. For example: &lt;code&gt;k6 cloud run --local-execution --no-archive-upload script.js&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;To learn more about Grafana Cloud k6, refer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/docs/grafana-cloud/testing/k6/&#34;&gt;Grafana Cloud k6 documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/use-the-cli/&#34;&gt;Use the CLI&lt;/a&gt; - Learn about the different methods available to run a k6 test in Grafana Cloud.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;run-a-test-in-your-infrastructure-with-the-k6-operator&#34;&gt;Run a test in your infrastructure with the k6 Operator&lt;/h2&gt;
&lt;p&gt;k6 Operator is a Kubernetes operator that you can use to run distributed k6 tests in your Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;A couple of reasons why you might want to do this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You run your application in Kubernetes and would like k6 to be executed in the same fashion as all your other infrastructure components.&lt;/li&gt;
&lt;li&gt;You want to run your tests within your private network for security or privacy reasons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To set up and run a test using the k6 Operator, refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/set-up/set-up-distributed-k6/&#34;&gt;Set up distributed k6&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="run-a-k6-test-script">Run a k6 test script&lt;/h1>
&lt;p>There are several ways you can use the Grafana k6 command-line tool (CLI) to run a k6 performance test. In this page, you&amp;rsquo;ll learn how to use each method and how they differ from each other.&lt;/p></description></item><item><title>Feature flags</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/feature-flags/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/feature-flags/</guid><content><![CDATA[&lt;h1 id=&#34;feature-flags&#34;&gt;Feature flags&lt;/h1&gt;
&lt;p&gt;Feature flags let you try k6 capabilities before they&amp;rsquo;re on by default. When a feature reaches general availability, it becomes the default and k6 removes the flag.&lt;/p&gt;
&lt;p&gt;Unlike operational configuration like &lt;code&gt;K6_WEB_DASHBOARD&lt;/code&gt;, flags are temporary. Operational config stays user-controllable indefinitely; flags get removed once their behavior is the default.&lt;/p&gt;
&lt;h2 id=&#34;discover-available-flags&#34;&gt;Discover available flags&lt;/h2&gt;
&lt;p&gt;The set of flags changes across k6 releases: some get promoted to defaults and disappear, new ones are added. Check which flags your k6 version supports before enabling one.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 features&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;FEATURE                LIFECYCLE      DESCRIPTION
async-metric-context   Experimental   Propagate metric context through asynchronous operations
freeze-env             Experimental   Freeze __ENV object to prevent modifications from JS code
merge-run-tags         Experimental   Merge run tags across config layers instead of replacing
native-histograms      Experimental   Use native histograms for trend metrics&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;async-metric-context&lt;/code&gt; flag propagates the tags and metadata associated with metric samples through asynchronous operations, including Promise reactions and timer callbacks. It also enables async callbacks for 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/group/&#34;&gt;&lt;code&gt;group()&lt;/code&gt;&lt;/a&gt;. This flag is experimental, off by default, and may change or be removed.&lt;/p&gt;
&lt;p&gt;Module-specific propagation applies to 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/asyncrequest/&#34;&gt;&lt;code&gt;http.asyncRequest()&lt;/code&gt;&lt;/a&gt;, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-timers/&#34;&gt;timers&lt;/a&gt;, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-websockets/&#34;&gt;&lt;code&gt;k6/websockets&lt;/code&gt;&lt;/a&gt;, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-net-grpc/stream/stream-on/&#34;&gt;gRPC stream handlers&lt;/a&gt;, and 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-browser/&#34;&gt;&lt;code&gt;k6/browser&lt;/code&gt;&lt;/a&gt;. Refer to each API page for its context-capture boundary and limitations.&lt;/p&gt;
&lt;p&gt;Add &lt;code&gt;--json&lt;/code&gt; to get machine-readable output, useful for scripting — for example, checking in CI whether a specific flag is available before enabling it:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 features --json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;[
  {
    &amp;#34;feature&amp;#34;: &amp;#34;native-histograms&amp;#34;,
    &amp;#34;lifecycle&amp;#34;: &amp;#34;Experimental&amp;#34;,
    &amp;#34;description&amp;#34;: &amp;#34;Use native histograms for trend metrics&amp;#34;
  }
]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;enabling-flags&#34;&gt;Enabling flags&lt;/h2&gt;
&lt;p&gt;k6 supports three ways to enable flags. Pick the one that fits your workflow.&lt;/p&gt;
&lt;h3 id=&#34;cli-flag&#34;&gt;CLI flag&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;--features&lt;/code&gt; to enable a flag for a single run, without touching your config or environment:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --features native-histograms script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Separate multiple flags with commas:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --features native-histograms,other-flag script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;environment-variable&#34;&gt;Environment variable&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;K6_FEATURES&lt;/code&gt; when your CI pipeline or shell environment controls which features are active, without changing your script or config file:&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Bash&#34;&gt;Bash&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;windows&#34;&gt;windows&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;powershell&#34;&gt;powershell&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;K6_FEATURES=native-histograms k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;windows&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-windows&#34;&gt;set &amp;#34;K6_FEATURES=native-histograms&amp;#34; &amp;amp;&amp;amp; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;powershell&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-powershell&#34;&gt;$env:K6_FEATURES=&amp;#34;native-histograms&amp;#34;; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Separate multiple flags with commas: &lt;code&gt;K6_FEATURES=native-histograms,other-flag&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;json-config-file&#34;&gt;JSON config file&lt;/h3&gt;
&lt;p&gt;Put flags in a config file to version-control them alongside your test suite and share them with your team:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;#34;features&amp;#34;: [&amp;#34;native-histograms&amp;#34;]
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --config config.json script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;precedence&#34;&gt;Precedence&lt;/h2&gt;
&lt;p&gt;If you set flags in more than one place, CLI wins over the environment variable, which wins over the config file. The winning source is used as-is; k6 ignores the others entirely. For example, if you pass &lt;code&gt;--features&lt;/code&gt;, k6 ignores &lt;code&gt;K6_FEATURES&lt;/code&gt; for that run.&lt;/p&gt;
&lt;h2 id=&#34;lifecycle-stages&#34;&gt;Lifecycle stages&lt;/h2&gt;
&lt;p&gt;A flag&amp;rsquo;s lifecycle stage tells you how stable it is and when to clean it up. Check the stage before relying on a flag in production or long-running CI.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Stage&lt;/th&gt;
              &lt;th&gt;Behavior&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;Experimental&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Off by default. Enable to try it. May change or be removed.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;GA&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;On by default. Passing the flag logs a reminder to remove it from your config.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;Deprecated&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Off by default. Removed in a future release.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;

&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If you pass a flag k6 doesn&amp;rsquo;t recognize (a typo or a flag removed after its grace period), k6 logs an &lt;code&gt;ERROR&lt;/code&gt; and the run continues. Watch your logs — the flag is not applied.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;migrate-from-legacy-environment-variables&#34;&gt;Migrate from legacy environment variables&lt;/h2&gt;
&lt;p&gt;Some features previously used their own environment variables. For example, &lt;code&gt;K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM&lt;/code&gt; maps to the &lt;code&gt;native-histograms&lt;/code&gt; flag. The old variable still works but logs a deprecation warning and will be removed in a future release. Switch to &lt;code&gt;K6_FEATURES=native-histograms&lt;/code&gt; or &lt;code&gt;--features native-histograms&lt;/code&gt; to avoid breakage when it&amp;rsquo;s gone.&lt;/p&gt;
&lt;h2 id=&#34;observability&#34;&gt;Observability&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re comparing test results across runs (for example, checking whether a feature improved tail latency), you need to know which features were active. k6 tags every metric sample with the active flags so you can filter and compare in your output.&lt;/p&gt;
&lt;p&gt;While a flag is active, every metric sample carries a tag &lt;code&gt;k6_feature_&amp;lt;name&amp;gt;=&amp;quot;true&amp;quot;&lt;/code&gt; (hyphens become underscores, for example &lt;code&gt;k6_feature_native_histograms=&amp;quot;true&amp;quot;&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;k6 also includes active flags in 
    &lt;a href=&#34;/docs/k6/v2.3.x/set-up/usage-collection/&#34;&gt;usage telemetry&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;running-on-grafana-cloud&#34;&gt;Running on Grafana Cloud&lt;/h2&gt;
&lt;p&gt;Feature flags work the same when you run tests through &lt;a href=&#34;/docs/grafana-cloud/testing/k6/&#34;&gt;Grafana Cloud k6&lt;/a&gt;. Set them with &lt;code&gt;--features&lt;/code&gt;, &lt;code&gt;K6_FEATURES&lt;/code&gt;, or a config file. Your test runs on the cloud with the same features active as locally.&lt;/p&gt;
&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/&#34;&gt;k6 options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/set-up/usage-collection/&#34;&gt;Usage collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="feature-flags">Feature flags&lt;/h1>
&lt;p>Feature flags let you try k6 capabilities before they&amp;rsquo;re on by default. When a feature reaches general availability, it becomes the default and k6 removes the flag.&lt;/p></description></item><item><title>HTTP Requests</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/http-requests/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/http-requests/</guid><content><![CDATA[&lt;h1 id=&#34;http-requests&#34;&gt;HTTP Requests&lt;/h1&gt;
&lt;p&gt;When you create a new load test, one of the first steps is to define the HTTP requests that you would like to test.&lt;/p&gt;
&lt;h2 id=&#34;making-http-requests&#34;&gt;Make HTTP Requests&lt;/h2&gt;
&lt;p&gt;A GET request looks like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  http.get(&amp;#39;http://test.k6.io&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For something slightly more complex, this example shows a POST request with an email/password authentication payload:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const url = &amp;#39;http://test.k6.io/login&amp;#39;;
  const payload = JSON.stringify({
    email: &amp;#39;aaa&amp;#39;,
    password: &amp;#39;bbb&amp;#39;,
  });

  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
  };

  http.post(url, payload, params);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;available-methods&#34;&gt;Available methods&lt;/h2&gt;
&lt;p&gt;The 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/&#34;&gt;http module&lt;/a&gt; handles all kinds of HTTP requests and methods.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Name&lt;/th&gt;
              &lt;th&gt;Value&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/batch/&#34;&gt;batch()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue multiple HTTP requests in parallel (like e.g. browsers tend to do).&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/del/&#34;&gt;del()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP DELETE request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/get/&#34;&gt;get()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP GET request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/head/&#34;&gt;head()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP HEAD request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/options/&#34;&gt;options()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP OPTIONS request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/patch/&#34;&gt;patch()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP PATCH request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/post/&#34;&gt;post()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP POST request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/put/&#34;&gt;put()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue an HTTP PUT request.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/request/&#34;&gt;request()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Issue any type of HTTP request.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;follow-redirects&#34;&gt;Follow redirects&lt;/h2&gt;
&lt;p&gt;By default, k6 automatically follows a set number of redirects before stopping and returning the last response. You can customize this by using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;maxRedirects&lt;/code&gt; option to customize the number of redirects globally. Refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#max-redirects&#34;&gt;Max redirects&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Params.redirects&lt;/code&gt; property to customize the number of redirects for a specific request, which overrides the &lt;code&gt;maxRedirects&lt;/code&gt; option. Refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/params/&#34;&gt;Params&lt;/a&gt; for more details.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;http-request-tags&#34;&gt;HTTP Request Tags&lt;/h2&gt;
&lt;p&gt;k6 automatically applies 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#section-tags&#34;&gt;tags&lt;/a&gt; to your HTTP requests.
You can use these tags to filter your results and organize your analysis.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Name&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;expected_response&lt;/td&gt;
              &lt;td&gt;By default, response statuses between 200 and 399 are &lt;code&gt;true&lt;/code&gt;. Change the default behavior with 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/set-response-callback/&#34;&gt;setResponseCallback&lt;/a&gt;.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;group&lt;/td&gt;
              &lt;td&gt;When the request runs inside a 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/group/&#34;&gt;group&lt;/a&gt;, the tag value is the group name. Default is empty.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;name&lt;/td&gt;
              &lt;td&gt;Defaults to URL requested&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;method&lt;/td&gt;
              &lt;td&gt;Request method (&lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt; etc.)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;scenario&lt;/td&gt;
              &lt;td&gt;When the request runs inside a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/&#34;&gt;scenario&lt;/a&gt;, the tag value is the scenario name. Default is &lt;code&gt;default&lt;/code&gt;.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;status&lt;/td&gt;
              &lt;td&gt;response status&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;url&lt;/td&gt;
              &lt;td&gt;defaults to URL requested&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;The following snippet shows a JSON example of how a test-result data point is logged.
In this example, the metric is the duration of an HTTP request.&lt;/p&gt;
&lt;p&gt;Note how the &lt;code&gt;tags&lt;/code&gt; object groups data.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;#34;type&amp;#34;: &amp;#34;Point&amp;#34;,
  &amp;#34;metric&amp;#34;: &amp;#34;http_req_duration&amp;#34;,
  &amp;#34;data&amp;#34;: {
    &amp;#34;time&amp;#34;: &amp;#34;2017-06-02T23:10:29.52444541&amp;#43;02:00&amp;#34;,
    &amp;#34;value&amp;#34;: 586.831127,
    &amp;#34;tags&amp;#34;: {
      &amp;#34;expected_response&amp;#34;: &amp;#34;true&amp;#34;,
      &amp;#34;group&amp;#34;: &amp;#34;&amp;#34;,
      &amp;#34;method&amp;#34;: &amp;#34;GET&amp;#34;,
      &amp;#34;name&amp;#34;: &amp;#34;http://test.k6.io&amp;#34;,
      &amp;#34;scenario&amp;#34;: &amp;#34;default&amp;#34;,
      &amp;#34;status&amp;#34;: &amp;#34;200&amp;#34;,
      &amp;#34;url&amp;#34;: &amp;#34;http://test.k6.io&amp;#34;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;url-grouping&#34;&gt;Group URLs under one tag&lt;/h2&gt;
&lt;p&gt;By default, tags have a &lt;code&gt;name&lt;/code&gt; field that holds the value of the request URL.
If your test has dynamic URL paths, you might not want this behavior, which could bring a large number of unique URLs into the metrics stream.
For example, the following code accesses 100 different URLs:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  for (let id = 1; id &amp;lt;= 100; id&amp;#43;&amp;#43;) {
    http.get(`http://example.com/posts/${id}`);
  }
}
// tags.name=\&amp;#34;http://example.com/posts/1\&amp;#34;,
// tags.name=\&amp;#34;http://example.com/posts/2\&amp;#34;,&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You might prefer to report this data in a single metric:
To aggregate data from dynamic URLs, explicitly set a &lt;code&gt;name&lt;/code&gt; tag:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  for (let id = 1; id &amp;lt;= 100; id&amp;#43;&amp;#43;) {
    http.get(`http://example.com/posts/${id}`, {
      tags: { name: &amp;#39;PostsItemURL&amp;#39; },
    });
  }
}
// tags.name=\&amp;#34;PostsItemURL\&amp;#34;,
// tags.name=\&amp;#34;PostsItemURL\&amp;#34;,&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That code would produce JSON output like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;// For http://example.com/1, note that the url is not present in the JSON.

{
    &amp;#34;type&amp;#34;:&amp;#34;Point&amp;#34;,
    &amp;#34;metric&amp;#34;:&amp;#34;http_req_duration&amp;#34;,
    &amp;#34;data&amp;#34;: {
        &amp;#34;time&amp;#34;:&amp;#34;2017-06-02T23:10:29.52444541&amp;#43;02:00&amp;#34;,
        &amp;#34;value&amp;#34;:586.831127,
        &amp;#34;tags&amp;#34;: {
            &amp;#34;method&amp;#34;:&amp;#34;GET&amp;#34;,
            &amp;#34;name&amp;#34;:&amp;#34;PostsItemURL&amp;#34;,
            &amp;#34;status&amp;#34;:&amp;#34;200&amp;#34;,
            &amp;#34;url&amp;#34;:&amp;#34;PostsItemURL&amp;#34;
        }
    }
}

// and for http://example.com/2

{
    &amp;#34;type&amp;#34;:&amp;#34;Point&amp;#34;,
    &amp;#34;metric&amp;#34;:&amp;#34;http_req_duration&amp;#34;,
    &amp;#34;data&amp;#34;: {
        &amp;#34;time&amp;#34;:&amp;#34;2017-06-02T23:10:29.58582529&amp;#43;02:00&amp;#34;,
        &amp;#34;value&amp;#34;:580.839273,
        &amp;#34;tags&amp;#34;: {
            &amp;#34;method&amp;#34;:&amp;#34;GET&amp;#34;,
            &amp;#34;name&amp;#34;:&amp;#34;PostsItemURL&amp;#34;,
            &amp;#34;status&amp;#34;:&amp;#34;200&amp;#34;,
            &amp;#34;url&amp;#34;:&amp;#34;PostsItemURL&amp;#34;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note how these two objects have the same &lt;code&gt;name&lt;/code&gt;, despite having different URLs.
If you filter the results for the tag &lt;code&gt;name: PostsItemURL&lt;/code&gt;, the results include all data points from all 100 URLs.&lt;/p&gt;
&lt;p&gt;As an alternative, you can also use the &lt;code&gt;http.url&lt;/code&gt; wrapper to set the &lt;code&gt;name&lt;/code&gt; tag with a string template value:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  for (let id = 1; id &amp;lt;= 100; id&amp;#43;&amp;#43;) {
    http.get(http.url`http://example.com/posts/${id}`);
  }
}
// tags.name=&amp;#34;http://example.com/posts/${}&amp;#34;,
// tags.name=&amp;#34;http://example.com/posts/${}&amp;#34;,&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="http-requests">HTTP Requests&lt;/h1>
&lt;p>When you create a new load test, one of the first steps is to define the HTTP requests that you would like to test.&lt;/p></description></item><item><title>Metrics</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/metrics/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/metrics/</guid><content><![CDATA[&lt;h1 id=&#34;metrics&#34;&gt;Metrics&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Metrics&lt;/em&gt; measure how a system performs under test conditions.
By default, k6 automatically collects built-in metrics.
Besides built-ins, you can also make custom metrics.&lt;/p&gt;
&lt;p&gt;Metrics fall into four broad types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Counters&lt;/strong&gt; sum values.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gauges&lt;/strong&gt; track the smallest, largest, and latest values.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rates&lt;/strong&gt; track how frequently a non-zero value occurs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trends&lt;/strong&gt; calculates statistics for multiple values (like mean, mode or percentile).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To make a test fail a certain criteria, you can write a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;Threshold&lt;/a&gt; based on the metric criteria (the specifics of the expression depend on the metric type).
To filter metrics, you can use 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/&#34;&gt;Tags and groups&lt;/a&gt;.
You can also export metrics in various summary and granular formats, as documented in 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/&#34;&gt;Results output&lt;/a&gt;.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;On this page&amp;hellip;&lt;/th&gt;
              &lt;th&gt;Read about&amp;hellip;&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/reference/&#34;&gt;Built-in metrics&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Each built-in metric for each supported 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/&#34;&gt;protocol&lt;/a&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/create-custom-metrics/&#34;&gt;Create custom metrics&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;How to build your own metric for each metric type&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;what-metrics-to-look-at&#34;&gt;What metrics to look at?&lt;/h2&gt;
&lt;p&gt;Each metric provides a different perspective on performance.
So the best metric for your analysis depends on your goals.&lt;/p&gt;
&lt;p&gt;However, if you&amp;rsquo;re unsure about the metrics to focus on, you can start with the metrics that measure the requests, errors, and duration (the criteria of the &lt;a href=&#34;/blog/2018/08/02/the-red-method-how-to-instrument-your-services/&#34;&gt;RED method&lt;/a&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http_reqs&lt;/code&gt;, to measure requests&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_req_failed&lt;/code&gt;, to measure error rate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_req_duration&lt;/code&gt;, to measure duration&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;In other terminology, these metrics measure traffic (in requests), availability (in error rate), and latency (in request duration).
SREs might recognize these metrics as three of the &lt;a href=&#34;https://sre.google/sre-book/monitoring-distributed-systems/#xref_monitoring_golden-signals&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;four Golden Signals&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;example-output&#34;&gt;Example output&lt;/h2&gt;
&lt;p&gt;An aggregated summary of all &lt;em&gt;built-in&lt;/em&gt; and custom metrics outputs to &lt;code&gt;stdout&lt;/code&gt; when you run a test:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The preceding script outputs something like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ k6 run script.js

         /\      Grafana   /‾‾/
    /\  /  \     |\  __   /  /
   /  \/    \    | |/ /  /   ‾‾\
  /          \   |   (  |  (‾)  |
 / __________ \  |_|\_\  \_____/


  execution: local
     script: http_get.js
     output: -

  scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
           * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)



  █ TOTAL RESULTS

    HTTP
    http_req_duration.......................................................: avg=117.55ms min=117.55ms med=117.55ms max=117.55ms p(90)=117.55ms p(95)=117.55ms
      { expected_response:true }............................................: avg=117.55ms min=117.55ms med=117.55ms max=117.55ms p(90)=117.55ms p(95)=117.55ms
    http_req_failed.........................................................: 0.00%  0 out of 1
    http_reqs...............................................................: 1      2.768749/s

    EXECUTION
    iteration_duration......................................................: avg=361.09ms min=361.09ms med=361.09ms max=361.09ms p(90)=361.09ms p(95)=361.09ms
    iterations..............................................................: 1      2.768749/s

    NETWORK
    data_received...........................................................: 6.8 kB 19 kB/s
    data_sent...............................................................: 541 B  1.5 kB/s

running (00m03.8s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  00m03.8s/10m0s  1/1 iters, 1 per VU&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In that output, all the metrics that start with &lt;code&gt;http&lt;/code&gt;, &lt;code&gt;iteration&lt;/code&gt;, and &lt;code&gt;vu&lt;/code&gt; are &lt;em&gt;built-in&lt;/em&gt; metrics, which get written to stdout at the end of a test.
For details of all metrics, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/reference/&#34;&gt;Metrics reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;metric-name-restrictions&#34;&gt;Metric name restrictions&lt;/h2&gt;
&lt;p&gt;Metric names must comply with OpenTelemetry and &lt;a href=&#34;https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Prometheus limitations&lt;/a&gt;. The character limit is the same limit k6 had before restricting the character set down.&lt;/p&gt;
&lt;p&gt;That means metrics names must:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Include up to 128 symbols (ASCII letters, numbers, or underscores).&lt;/li&gt;
&lt;li&gt;Start with a letter or an underscore.&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="metrics">Metrics&lt;/h1>
&lt;p>&lt;em>Metrics&lt;/em> measure how a system performs under test conditions.
By default, k6 automatically collects built-in metrics.
Besides built-ins, you can also make custom metrics.&lt;/p></description></item><item><title>Checks</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/checks/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/checks/</guid><content><![CDATA[&lt;h1 id=&#34;checks&#34;&gt;Checks&lt;/h1&gt;
&lt;p&gt;Checks validate boolean conditions in your test.
Testers often use checks to validate that the system is responding with the expected content.
For example, a check could validate that a POST request has a &lt;code&gt;response.status == 201&lt;/code&gt;, or that the body is of a certain size.&lt;/p&gt;
&lt;p&gt;Checks are similar to what many testing frameworks call an &lt;em&gt;assert&lt;/em&gt;, but &lt;strong&gt;failed checks do not cause the test to abort or finish with a failed status&lt;/strong&gt;.
Instead, k6 keeps track of the rate of failed checks as the test continues to run&lt;/p&gt;
&lt;p&gt;Each check creates a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/&#34;&gt;rate metric&lt;/a&gt;.
To make a check abort or fail a test, you can combine it with a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;Threshold&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;check-for-http-response-code&#34;&gt;Check for HTTP response code&lt;/h2&gt;
&lt;p&gt;Checks are great for codifying assertions relating to HTTP requests and responses.
For example, this snippet makes sure the HTTP response code is a 200:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const res = http.get(&amp;#39;http://test.k6.io/&amp;#39;);
  check(res, {
    &amp;#39;is status 200&amp;#39;: (r) =&amp;gt; r.status === 200,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;check-for-text-in-response-body&#34;&gt;Check for text in response body&lt;/h2&gt;
&lt;p&gt;Sometimes, even an HTTP 200 response contains an error message.
In these situations, consider adding a check to verify the response body, like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const res = http.get(&amp;#39;http://test.k6.io/&amp;#39;);
  check(res, {
    &amp;#39;verify homepage text&amp;#39;: (r) =&amp;gt;
      r.body.includes(&amp;#39;Collection of simple web-pages suitable for load testing&amp;#39;),
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;check-for-response-body-size&#34;&gt;Check for response body size&lt;/h2&gt;
&lt;p&gt;To verify the size of the response body, you can use a check like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const res = http.get(&amp;#39;http://test.k6.io/&amp;#39;);
  check(res, {
    &amp;#39;body size is 11,105 bytes&amp;#39;: (r) =&amp;gt; r.body.length == 11105,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;see-percentage-of-checks-that-passed&#34;&gt;See percentage of checks that passed&lt;/h2&gt;
&lt;p&gt;When a script includes checks, the summary report shows how many of the tests&amp;rsquo; checks passed. The check built-in metric is split into three separate metrics: &lt;code&gt;checks_total&lt;/code&gt;, &lt;code&gt;checks_succeeded&lt;/code&gt;, and &lt;code&gt;checks_failed&lt;/code&gt;.:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ k6 run script.js

  ...
    ✓ is status 200

  ...
  checks_total.......................: 1       1.23/s
  checks_succeeded...................: 100.00% 1 out of 1
  checks_failed......................: 0.00%   0 out of 1
  ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example, note that the check &amp;ldquo;is status 200&amp;rdquo; succeeded 100% of the times it was called.&lt;/p&gt;
&lt;h2 id=&#34;add-multiple-checks&#34;&gt;Add multiple checks&lt;/h2&gt;
&lt;p&gt;You can also add multiple checks within a single 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/check/&#34;&gt;check()&lt;/a&gt; statement:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const res = http.get(&amp;#39;http://test.k6.io/&amp;#39;);
  check(res, {
    &amp;#39;is status 200&amp;#39;: (r) =&amp;gt; r.status === 200,
    &amp;#39;body size is 11,105 bytes&amp;#39;: (r) =&amp;gt; r.body.length == 11105,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When this test executes, the output will look something like this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ k6 run checks.js

  ...
    ✓ is status 200
    ✓ body size is 11,105 bytes

  ...
  checks_total.......................: 2       2.34/s
  checks_succeeded...................: 100.00% 2 out of 2
  checks_failed......................: 0.00%   0 out of 2
  ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;When a check fails, the script will continue executing successfully and will not return a &amp;lsquo;failed&amp;rsquo; exit status.
If you need the whole test to fail based on the results of a check, you have to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/#fail-a-load-test-using-checks&#34;&gt;combine checks with thresholds&lt;/a&gt;.
This is particularly useful in specific contexts, such as integrating k6 into your CI pipelines or receiving alerts when scheduling your performance tests.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/check/&#34;&gt;Check Javascript API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/#fail-a-load-test-using-checks&#34;&gt;Failing a load test using checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/k6chaijs/&#34;&gt;k6chaijs&lt;/a&gt;: use BDD assertions in k6&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="checks">Checks&lt;/h1>
&lt;p>Checks validate boolean conditions in your test.
Testers often use checks to validate that the system is responding with the expected content.
For example, a check could validate that a POST request has a &lt;code>response.status == 201&lt;/code>, or that the body is of a certain size.&lt;/p></description></item><item><title>Assertions</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/assertions/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/assertions/</guid><content><![CDATA[

&lt;div data-shared=&#34;preview-feature.md&#34;&gt;
            

&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;This is a &lt;strong&gt;preview&lt;/strong&gt; feature.
&lt;br&gt;
&lt;br&gt;
While we&amp;rsquo;re committed to supporting and maintaining this feature in the future (we do not anticipate breaking changes) some functionality might be missing; it might be a bit rough around the edges; and there might be use-cases we haven&amp;rsquo;t covered yet. The feature is considered ready to use, but it is in a preview state as we expect to keep iterating on it by adding new functionalities and improvements.
&lt;br&gt;
&lt;br&gt;
Users are encouraged to participate in its roadmap and implementation on &lt;a href=&#34;https://github.com/grafana/k6-jslib-testing&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;GitHub&lt;/a&gt;. Feel free to &lt;a href=&#34;https://github.com/grafana/k6/issues&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;open an issue&lt;/a&gt; if you have any feedback or suggestions.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;/div&gt;

        
&lt;h1 id=&#34;assertions&#34;&gt;Assertions&lt;/h1&gt;
&lt;p&gt;k6 provides test assertions in the form of the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/expect/&#34;&gt;&lt;code&gt;expect&lt;/code&gt;&lt;/a&gt; function. Assertions validate that your application behaves as expected during testing.&lt;/p&gt;
&lt;p&gt;Define assertions by passing a value to 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/expect/&#34;&gt;&lt;code&gt;expect()&lt;/code&gt;&lt;/a&gt; and chaining it with a matcher that defines your expected outcome. The library provides expressive matchers that work with both protocol testing 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/&#34;&gt;HTTP/API&lt;/a&gt; and 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6-browser/&#34;&gt;browser&lt;/a&gt; testing scenarios.&lt;/p&gt;
&lt;p&gt;The assertions API is inspired by Playwright&amp;rsquo;s assertion syntax, providing a fluent interface that improves test readability and reliability.&lt;/p&gt;
&lt;h2 id=&#34;getting-started&#34;&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Assertions are provided by the &lt;a href=&#34;https://jslib.k6.io&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-testing library&lt;/a&gt;. Import the library to start using assertions:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import { browser } from &amp;#39;k6/browser&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export function protocolTest() {
  // Get the home page of k6&amp;#39;s Quick Pizza app
  const response = http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

  // Simple assertions
  expect(response.status).toBe(200);
  expect(response.error).toEqual(&amp;#39;&amp;#39;);
  expect(response.body).toBeDefined();
}

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

  try {
    await page.goto(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

    // Assert the &amp;#34;Pizza Please&amp;#34; button is visible
    await expect(page.locator(&amp;#39;button[name=pizza-please]&amp;#39;)).toBeVisible();
  } finally {
    await page.close();
  }
}

export const options = {
  scenarios: {
    // Protocol tests
    protocol: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      vus: 1,
      iterations: 1,
      exec: &amp;#39;protocolTest&amp;#39;,
    },

    // Browser tests
    ui: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      options: {
        browser: {
          type: &amp;#39;chromium&amp;#39;,
        },
      },
      exec: &amp;#39;browserTest&amp;#39;,
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;types-of-assertions&#34;&gt;Types of assertions&lt;/h2&gt;
&lt;p&gt;The k6-testing library provides two types of assertions, each designed for different testing scenarios:&lt;/p&gt;
&lt;h3 id=&#34;non-retrying-assertions&#34;&gt;Non-retrying assertions&lt;/h3&gt;
&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/&#34;&gt;Non-retrying assertions&lt;/a&gt; evaluate conditions immediately at a single point in time without retrying. They&amp;rsquo;re ideal for validating static data such as HTTP response content, data structures, or configuration values.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const pizzaRequestPayload = { maxCaloriesPerSlice: 1000, mustBeVegetarian: true };
  const pizzaRequestHeader = {
    &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    &amp;#39;Authorization&amp;#39;: &amp;#39;Token &amp;#39; &amp;#43; &amp;#39;abcdef0123456789&amp;#39;,
  };

  const response = http.post(
    `https://quickpizza.grafana.com/api/pizza`,
    JSON.stringify(pizzaRequestPayload),
    { headers: pizzaRequestHeader }
  );
  const data = response.json();

  // These assertions evaluate immediately
  expect(response.status).toEqual(200);
  expect(response.headers[&amp;#39;Content-Type&amp;#39;]).toBeDefined();
  expect(response.headers[&amp;#39;Content-Type&amp;#39;]).toEqual(&amp;#39;application/json&amp;#39;);
  expect(data.pizza).toBeDefined();
  expect(data.pizza.name).toBeDefined();
  expect(data.pizza.name).not.toHaveLength(0);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;auto-retrying-assertions&#34;&gt;Auto-retrying assertions&lt;/h3&gt;
&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/&#34;&gt;Auto-retrying assertions&lt;/a&gt; automatically retry until conditions become true or a timeout is reached. They&amp;rsquo;re designed for 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6-browser/&#34;&gt;browser testing&lt;/a&gt; scenarios where elements may take time to load, update, or become interactable.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import { browser } from &amp;#39;k6/browser&amp;#39;;

export default async function () {
  // Open a new browser page
  const page = await browser.newPage();

  try {
    // Navigate to the quickpizza website
    await page.goto(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

    // Click the &amp;#39;Pizza please&amp;#39; button
    await page.locator(&amp;#39;button[name=&amp;#34;pizza-please&amp;#34;]&amp;#39;).click();

    // Take a screenshot of the homepage, and save it to the local filesystem
    // so we can inspect it later if needed.
    await page.screenshot({ path: &amp;#39;homepage.png&amp;#39; });

    // Check if the pizza recipe is displayed
    const textContent = await pizzaRecipeIsDisplayed(page);
    expect(textContent).toEqual(&amp;#39;Our recommendation:&amp;#39;);
  } finally {
    await page.close();
  }
}

// Browsers are asynchronous, so we need to wait for the content we want to check
// to be visible.
async function pizzaRecipeIsDisplayed(page) {
  const label = await page.locator(&amp;#39;h2[id=&amp;#34;pizza-name&amp;#34;]&amp;#39;);
  await label.isVisible();
  const textContent = (await label.textContent()).trim();

  return textContent;
}

export const options = {
  scenarios: {
    ui: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      options: {
        browser: {
          type: &amp;#39;chromium&amp;#39;,
        },
      },
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;assertions-vs-checks&#34;&gt;Assertions vs. checks&lt;/h2&gt;
&lt;p&gt;Unlike k6 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;checks&lt;/a&gt;, which continue execution when they fail and register metrics for threshold evaluation, assertions immediately fail and interrupt the test when expectations are not met. Assertions are designed for validating critical conditions that determine whether a test should continue—when these conditions aren&amp;rsquo;t met, they invalidate the entire testing scenario.&lt;/p&gt;
&lt;p&gt;Assertions do not register metrics because they halt execution rather than collect data points. This design provides fast feedback and detailed error messages to help you identify issues quickly, ensuring your tests only proceed when fundamental assumptions are satisfied.&lt;/p&gt;
&lt;h2 id=&#34;available-assertion-methods&#34;&gt;Available assertion methods&lt;/h2&gt;
&lt;h3 id=&#34;non-retrying-assertions-1&#34;&gt;Non-retrying assertions&lt;/h3&gt;
&lt;p&gt;Use these for immediate evaluation of static values:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Method&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobe/&#34;&gt;toBe()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Exact equality using Object.is()&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/toequal/&#34;&gt;toEqual()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Deep equality comparison&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobetruthy/&#34;&gt;toBeTruthy()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is truthy&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobefalsy/&#34;&gt;toBeFalsy()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is falsy&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobedefined/&#34;&gt;toBeDefined()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is not undefined&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobeundefined/&#34;&gt;toBeUndefined()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is undefined&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobenull/&#34;&gt;toBeNull()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is null&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobegreaterthan/&#34;&gt;toBeGreaterThan()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Numeric greater than&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobegreaterthanorequal/&#34;&gt;toBeGreaterThanOrEqual()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Numeric greater than or equal&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobelessthan/&#34;&gt;toBeLessThan()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Numeric less than&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobelessthanorequal/&#34;&gt;toBeLessThanOrEqual()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Numeric less than or equal&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobecloseto/&#34;&gt;toBeCloseTo()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Floating point comparison&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tocontain/&#34;&gt;toContain()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Array/string contains value&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tocontainequal/&#34;&gt;toContainEqual()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Array contains object with matching content&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tohavelength/&#34;&gt;toHaveLength()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Array/string has specific length&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tohaveproperty/&#34;&gt;toHaveProperty()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Object has specific property&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/tobeinstanceof/&#34;&gt;toBeInstanceOf()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Value is instance of class&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/&#34;&gt;See all non-retrying assertions →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;auto-retrying-assertions-1&#34;&gt;Auto-retrying assertions&lt;/h3&gt;
&lt;p&gt;Essential for browser testing with dynamic content:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Method&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobevisible/&#34;&gt;toBeVisible()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element is visible on the page&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobehidden/&#34;&gt;toBeHidden()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element is hidden or not visible&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobeenabled/&#34;&gt;toBeEnabled()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element is enabled and interactive&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobedisabled/&#34;&gt;toBeDisabled()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element is disabled&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobechecked/&#34;&gt;toBeChecked()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Checkbox or radio button is checked&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tobeeditable/&#34;&gt;toBeEditable()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element is editable&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tohavetext/&#34;&gt;toHaveText()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element has specific text content&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tocontaintext/&#34;&gt;toContainText()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element contains specific text&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tohavevalue/&#34;&gt;toHaveValue()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Input element has specific value&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/tohaveattribute/&#34;&gt;toHaveAttribute()&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Element has specific attribute value&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/&#34;&gt;See all retrying assertions →&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;assertion-features&#34;&gt;Assertion features&lt;/h2&gt;
&lt;h3 id=&#34;negation&#34;&gt;Negation&lt;/h3&gt;
&lt;p&gt;All assertions can be negated using &lt;code&gt;.not&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { browser } from &amp;#39;k6/browser&amp;#39;;
import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default async function () {
  const response = http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

  // Negated assertions
  expect(response.status).not.toBe(404);
  expect(response.body).not.toHaveLength(0);
  expect(response.headers).not.toHaveProperty(&amp;#39;error&amp;#39;);

  // Browser negation (with await)
  const page = await browser.newPage();
  await page.goto(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

  await expect(page.locator(&amp;#39;.error-message&amp;#39;)).not.toBeVisible();
}

export const options = {
  scenarios: {
    ui: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      options: {
        browser: {
          type: &amp;#39;chromium&amp;#39;,
        },
      },
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;soft-assertions&#34;&gt;Soft assertions&lt;/h3&gt;
&lt;p&gt;Soft assertions continue test execution even when they fail, marking the test as failed but allowing subsequent assertions to run. Unlike 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;checks&lt;/a&gt;, soft assertions do not measure failures or emit dedicated metrics. If you need failure-related metrics, consider using 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;checks&lt;/a&gt; instead:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const response = http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);

  // These will all run even if some fail
  expect.soft(response.status).toBe(200);
  expect.soft(response.headers[&amp;#39;Content-Type&amp;#39;]).toContain(&amp;#39;text/html&amp;#39;);
  expect.soft(response.body).toHaveLength(response.body.length);

  // Test continues and performs additional checks
  console.log(&amp;#39;Test completed, checking results...&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;custom-error-messages&#34;&gt;Custom error messages&lt;/h3&gt;
&lt;p&gt;Provide descriptive error messages for better debugging:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const response = http.get(&amp;#39;https://quickpizza.grafana.com/api/pizza&amp;#39;, {
    headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39; },
  });
  const pizza = response.json();

  expect(response.status, &amp;#39;API should return successful response&amp;#39;).toBe(200);
  expect(pizza.name, &amp;#39;Pizza should have a valid name&amp;#39;).toBeDefined();
  expect(pizza.name, &amp;#39;Pizza name should not be empty&amp;#39;).not.toHaveLength(0);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;configuration-and-customization&#34;&gt;Configuration and customization&lt;/h2&gt;
&lt;h3 id=&#34;global-configuration&#34;&gt;Global configuration&lt;/h3&gt;
&lt;p&gt;Configure assertion behavior globally for all tests:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

// Configure global settings
const configuredExpect = expect.configure({
  timeout: 10000, // 10 seconds for retrying assertions
  interval: 500, // Retry check every 500ms (on retriable assertions)
  colorize: true, // Enable colored output

  // Setting `softMode` to &amp;#39;throw&amp;#39;, will make soft assertions fail the current iteration instead of the whole test.
  softMode: &amp;#39;fail&amp;#39;,
});

export default function () {
  const response = http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);

  // All assertions use these settings
  configuredExpect(response.status).toBe(200);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;per-scenario-configuration&#34;&gt;Per-scenario configuration&lt;/h3&gt;
&lt;p&gt;Create different configurations for different test scenarios:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { expect } from &amp;#39;https://jslib.k6.io/k6-testing/0.6.1/index.js&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;
import { browser } from &amp;#39;k6/browser&amp;#39;;

// Fast assertions for API testing
const fastExpect = expect.configure({
  timeout: 2000,
  interval: 100,
});

// Slow assertions for complex browser interactions
const slowExpect = expect.configure({
  timeout: 30000,
  interval: 1000,
  softMode: &amp;#39;continue&amp;#39;,
});

export default async function () {
  // Use appropriate expectation based on test type
  const response = http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);
  fastExpect(response.status).toBe(200);

  if (__ENV.BROWSER_TEST) {
    const page = await browser.newPage();
    await page.goto(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);
    await slowExpect(page.locator(&amp;#39;h1&amp;#39;)).toBeVisible();
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;best-practices&#34;&gt;Best practices&lt;/h2&gt;
&lt;p&gt;For tests that primarily use assertions to validate system state, such as tests verifying a successful deployment in CI pipelines, run k6 tests with assertions in quiet mode:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --quiet --summary-mode=disabled script.ts&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This approach eliminates unnecessary output and focuses on the assertion results, making it ideal for automated testing environments.&lt;/p&gt;
&lt;h2 id=&#34;see-also&#34;&gt;See also&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/expect/&#34;&gt;expect() API reference&lt;/a&gt; - Complete assertion documentation&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/retrying-assertions/&#34;&gt;Auto-retrying assertions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/testing/non-retrying-assertions/&#34;&gt;Non-retrying assertions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6-browser/&#34;&gt;Browser testing&lt;/a&gt; - Browser automation with k6&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;Checks&lt;/a&gt; - Alternative validation approach&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;div data-shared="preview-feature.md">
&lt;div class="admonition admonition-note">&lt;blockquote>&lt;p class="title text-uppercase">Note&lt;/p>&lt;p>This is a &lt;strong>preview&lt;/strong> feature.
&lt;br>
&lt;br>
While we&amp;rsquo;re committed to supporting and maintaining this feature in the future (we do not anticipate breaking changes) some functionality might be missing; it might be a bit rough around the edges; and there might be use-cases we haven&amp;rsquo;t covered yet. The feature is considered ready to use, but it is in a preview state as we expect to keep iterating on it by adding new functionalities and improvements.
&lt;br>
&lt;br>
Users are encouraged to participate in its roadmap and implementation on &lt;a href="https://github.com/grafana/k6-jslib-testing" target="_blank" rel="noopener noreferrer">GitHub&lt;/a>. Feel free to &lt;a href="https://github.com/grafana/k6/issues" target="_blank" rel="noopener noreferrer">open an issue&lt;/a> if you have any feedback or suggestions.&lt;/p></description></item><item><title>Thresholds</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/thresholds/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/thresholds/</guid><content><![CDATA[&lt;h1 id=&#34;thresholds&#34;&gt;Thresholds&lt;/h1&gt;
&lt;p&gt;Thresholds are the pass/fail criteria that you define for your test metrics.
If the performance of the system under test (SUT) does not meet the conditions of your threshold,
&lt;strong&gt;the test finishes with a failed status.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Often, testers use thresholds to codify their SLOs.
For example, you can create thresholds for any combination of the following expectations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Less than 1% of requests return an error.&lt;/li&gt;
&lt;li&gt;95% of requests have a response time below 200ms.&lt;/li&gt;
&lt;li&gt;99% of requests have a response time below 400ms.&lt;/li&gt;
&lt;li&gt;A specific endpoint always responds within 300ms.&lt;/li&gt;
&lt;li&gt;Any conditions for a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/create-custom-metrics/&#34;&gt;custom metric&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thresholds are also essential for 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/automated-performance-testing/&#34;&gt;load-testing automation&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Give your test a threshold.&lt;/li&gt;
&lt;li&gt;Automate your execution&lt;/li&gt;
&lt;li&gt;Set up alerts for test failures.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that, you need to worry about the test only after your SUT fails to meet its performance expectations.&lt;/p&gt;
&lt;h2 id=&#34;thresholds-example-for-http-errors-and-response-duration&#34;&gt;Thresholds example for HTTP errors and response duration&lt;/h2&gt;
&lt;p&gt;This sample script specifies two thresholds.
One threshold evaluates the rate of HTTP errors (&lt;code&gt;http_req_failed&lt;/code&gt; metric).
The other evaluates whether 95 percent of responses happen within a certain duration (the &lt;code&gt;http_req_duration&lt;/code&gt; metric).&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export const options = {
  thresholds: {
    http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;], // http errors should be less than 1%
    http_req_duration: [&amp;#39;p(95)&amp;lt;200&amp;#39;], // 95% of requests should be below 200ms
  },
};

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In other words, when you define your threshold, specify an expression for a &lt;code&gt;pass&lt;/code&gt; criteria.
If that expression evaluates to &lt;code&gt;false&lt;/code&gt; at the end of the test, k6 considers the whole test a &lt;code&gt;fail&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After executing that script, k6 outputs something similar to this:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;  █ THRESHOLDS

    http_req_duration
    ✓ &amp;#39;p(95)&amp;lt;200&amp;#39; p(95)=148.21ms

    http_req_failed
    ✓ &amp;#39;rate&amp;lt;0.01&amp;#39; rate=0.05%

  █ TOTAL RESULTS

    HTTP
    http_req_duration..............: avg=151.06ms min=151.06ms med=151.06ms max=151.06ms p(90)=151.06ms p(95)=151.06ms
       { expected_response:true }..: avg=151.06ms min=151.06ms med=151.06ms max=151.06ms p(90)=151.06ms p(95)=151.06ms
    http_req_failed................: 0.00%  ✓ 0 ✗ 1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this case, the test met the criteria for both thresholds.
k6 considers this test a &lt;code&gt;pass&lt;/code&gt; and exits with an exit code &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If any of the thresholds had failed, the little green checkmark &lt;span style=&#34;color:green; font-weight:bold&#34;&gt;✓&lt;/span&gt; next to the threshold name
(&lt;code&gt;http_req_failed&lt;/code&gt;, &lt;code&gt;http_req_duration&lt;/code&gt;) would be a red cross &lt;span style=&#34;color:red; font-weight:bold&#34;&gt;✗&lt;/span&gt;
and k6 would exit with a non-zero exit code.&lt;/p&gt;
&lt;h2 id=&#34;threshold-syntax&#34;&gt;Threshold Syntax&lt;/h2&gt;
&lt;p&gt;To use a threshold, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;code&gt;thresholds&lt;/code&gt; property of the &lt;code&gt;options&lt;/code&gt; object, set a key using the name of the metric you want the threshold for:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    /* ... */
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define at least one threshold expression. You can do this in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The short format puts all threshold expressions as strings in an array.&lt;/li&gt;
&lt;li&gt;The long format puts each threshold in an object, with extra properties to &lt;a href=&#34;#abort-a-test-when-a-threshold-is-crossed&#34;&gt;abort on failure&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    //short format
    METRIC_NAME1: [&amp;#39;THRESHOLD_EXPRESSION&amp;#39;, `...`],
    //long format
    METRIC_NAME2: [
      {
        threshold: &amp;#39;THRESHOLD_EXPRESSION&amp;#39;,
        abortOnFail: true, // boolean
        delayAbortEval: &amp;#39;10s&amp;#39;, // string
      },
    ], // full format
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that &lt;code&gt;METRIC_NAME1&lt;/code&gt; and &lt;code&gt;THRESHOLD_EXPRESSION&lt;/code&gt; are placeholders.
The real text must be the name of the metric and the threshold expression.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This declaration configures thresholds for the metrics &lt;code&gt;metric_name1&lt;/code&gt; and &lt;code&gt;metric_name2&lt;/code&gt;.
To determine whether the threshold passes or fails, the script evaluates the &lt;code&gt;&#39;threshold_expression&#39;.&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;threshold-expression-syntax&#34;&gt;Threshold expression syntax&lt;/h3&gt;
&lt;p&gt;A threshold expression evaluates to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.
The threshold expression must be in the following format:&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;&amp;lt;aggregation_method&amp;gt; &amp;lt;operator&amp;gt; &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Some examples of threshold expressions are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;avg &amp;lt; 200&lt;/code&gt; // average duration must be less than 200ms&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count &amp;gt;= 500&lt;/code&gt; // count must be larger than or equal to 500&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p(90) &amp;lt; 300&lt;/code&gt; // 90% of samples must be below 300&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;aggregation-methods-by-type&#34;&gt;Aggregation methods by type&lt;/h3&gt;
&lt;p&gt;k6 aggregates metrics according to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/&#34;&gt;their type&lt;/a&gt;.
These aggregation methods form part of the threshold expressions.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Metric type&lt;/th&gt;
              &lt;th&gt;Aggregation methods&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;Counter&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;count&lt;/code&gt; and &lt;code&gt;rate&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Gauge&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Rate&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;rate&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Trend&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;avg&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;med&lt;/code&gt; and &lt;code&gt;p(N)&lt;/code&gt; where &lt;code&gt;N&lt;/code&gt; specifies the threshold percentile value, expressed as a number between 0.0 and 100. E.g. &lt;code&gt;p(99.99)&lt;/code&gt; means the 99.99th percentile. The values are in milliseconds.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;A percentile value outside the &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;100&lt;/code&gt; range (or &lt;code&gt;NaN&lt;/code&gt;) fails parsing with an error, so the test stops before running.&lt;/p&gt;
&lt;p&gt;This (slightly contrived) sample script uses all different types of metrics,
setting different types of thresholds for each:&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { Trend, Rate, Counter, Gauge } from &amp;#39;k6/metrics&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export const TrendRTT = new Trend(&amp;#39;RTT&amp;#39;);
export const RateContentOK = new Rate(&amp;#39;ContentOK&amp;#39;);
export const GaugeContentSize = new Gauge(&amp;#39;ContentSize&amp;#39;);
export const CounterErrors = new Counter(&amp;#39;Errors&amp;#39;);
export const options = {
  thresholds: {
    // Count: Incorrect content cannot be returned more than 99 times.
    Errors: [&amp;#39;count&amp;lt;100&amp;#39;],
    // Gauge: returned content must be smaller than 4000 bytes
    ContentSize: [&amp;#39;value&amp;lt;4000&amp;#39;],
    // Rate: content must be OK more than 95 times
    ContentOK: [&amp;#39;rate&amp;gt;0.95&amp;#39;],
    // Trend: Percentiles, averages, medians, and minimums
    // must be within specified milliseconds.
    RTT: [&amp;#39;p(99)&amp;lt;300&amp;#39;, &amp;#39;p(70)&amp;lt;250&amp;#39;, &amp;#39;avg&amp;lt;200&amp;#39;, &amp;#39;med&amp;lt;150&amp;#39;, &amp;#39;min&amp;lt;100&amp;#39;],
  },
};

export default function () {
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/json?name=Bert&amp;#39;);
  const contentOK = res.json(&amp;#39;name&amp;#39;) === &amp;#39;Bert&amp;#39;;

  TrendRTT.add(res.timings.duration);
  RateContentOK.add(contentOK);
  GaugeContentSize.add(res.body.length);
  CounterErrors.add(!contentOK);

  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-caution&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Caution&lt;/p&gt;&lt;p&gt;Do not specify multiple thresholds for the same metric by repeating the same object key.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;Since thresholds are defined as the properties of a JavaScript object, you can&amp;rsquo;t specify multiple ones with the same property name.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    // don&amp;#39;t use the same metric more than once here
    metric_name: [&amp;#39;count&amp;lt;100&amp;#39;],
    metric_name: [&amp;#39;rate&amp;lt;50&amp;#39;],
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The rest will be &lt;strong&gt;silently&lt;/strong&gt; ignored.
If you want to set multiple thresholds for a metric, specify them with an 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/#multiple-thresholds-on-a-single-metric&#34;&gt;array for the same key&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;threshold-examples-to-copy-and-paste&#34;&gt;Threshold examples to copy and paste&lt;/h2&gt;
&lt;p&gt;The quickest way to start with thresholds is to use the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/reference/&#34;&gt;built-in metrics&lt;/a&gt;.
Here are a few copy-paste examples that you can start using right away.&lt;/p&gt;
&lt;p&gt;For more specific threshold examples, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-metrics/counter/#counter-usage-in-thresholds&#34;&gt;Counter&lt;/a&gt;, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-metrics/gauge/#gauge-usage-in-thresholds&#34;&gt;Gauge&lt;/a&gt;, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-metrics/trend/#trend-usage-in-thresholds&#34;&gt;Trend&lt;/a&gt; and 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-metrics/rate/#rate-usage-in-thresholds&#34;&gt;Rate&lt;/a&gt; pages.&lt;/p&gt;
&lt;h3 id=&#34;a-percentile-of-requests-finishes-in-a-specified-duration&#34;&gt;A percentile of requests finishes in a specified duration&lt;/h3&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  thresholds: {
    // 90% of requests must finish within 400ms.
    http_req_duration: [&amp;#39;p(90) &amp;lt; 400&amp;#39;],
  },
};

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;error-rate-is-lower-than-1-percent&#34;&gt;Error rate is lower than 1 percent&lt;/h3&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  thresholds: {
    // During the whole test execution, the error rate must be lower than 1%.
    http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;],
  },
};

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;multiple-thresholds-on-a-single-metric&#34;&gt;Multiple thresholds on a single metric&lt;/h3&gt;
&lt;p&gt;You can also apply multiple thresholds for one metric.
This threshold has different duration requirements for different request percentiles.&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  thresholds: {
    // 90% of requests must finish within 400ms, 95% within 800, and 99.9% within 2s.
    http_req_duration: [&amp;#39;p(90) &amp;lt; 400&amp;#39;, &amp;#39;p(95) &amp;lt; 800&amp;#39;, &amp;#39;p(99.9) &amp;lt; 2000&amp;#39;],
  },
};

export default function () {
  const res1 = http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;threshold-on-group-duration&#34;&gt;Threshold on group duration&lt;/h3&gt;
&lt;p&gt;You can set thresholds per 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#groups&#34;&gt;Group&lt;/a&gt;.
This code has groups for individual requests and batch requests.
For each group, there are different thresholds.&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  thresholds: {
    &amp;#39;group_duration{group:::individualRequests}&amp;#39;: [&amp;#39;avg &amp;lt; 400&amp;#39;],
    &amp;#39;group_duration{group:::batchRequests}&amp;#39;: [&amp;#39;avg &amp;lt; 200&amp;#39;],
  },
  vus: 1,
  duration: &amp;#39;10s&amp;#39;,
};

export default function () {
  group(&amp;#39;individualRequests&amp;#39;, function () {
    http.get(&amp;#39;https://quickpizza.grafana.com/api/json?letter=a&amp;#39;);
    http.get(&amp;#39;https://quickpizza.grafana.com/api/json?letter=b&amp;#39;);
    http.get(&amp;#39;https://quickpizza.grafana.com/api/json?letter=c&amp;#39;);
  });

  group(&amp;#39;batchRequests&amp;#39;, function () {
    http.batch([
      [&amp;#39;GET&amp;#39;, &amp;#39;https://quickpizza.grafana.com/api/json?letter=a&amp;#39;],
      [&amp;#39;GET&amp;#39;, &amp;#39;https://quickpizza.grafana.com/api/json?letter=b&amp;#39;],
      [&amp;#39;GET&amp;#39;, &amp;#39;https://quickpizza.grafana.com/api/json?letter=c&amp;#39;],
    ]);
  });

  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;set-thresholds-for-specific-tags&#34;&gt;Set thresholds for specific tags&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s often useful to specify thresholds on a single URL or specific tag.
In k6, tagged requests create sub-metrics that you can use in thresholds:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    &amp;#39;metric_name{tag_name:tag_value}&amp;#39;: [&amp;#39;threshold_expression&amp;#39;],
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;And here&amp;rsquo;s a full example.&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;
import { Rate } from &amp;#39;k6/metrics&amp;#39;;

export const options = {
  thresholds: {
    &amp;#39;http_req_duration{type:API}&amp;#39;: [&amp;#39;p(95)&amp;lt;500&amp;#39;], // threshold on API requests only
    &amp;#39;http_req_duration{type:staticContent}&amp;#39;: [&amp;#39;p(95)&amp;lt;200&amp;#39;], // threshold on static content only
  },
};

export default function () {
  const res1 = http.get(&amp;#39;https://quickpizza.grafana.com/api/headers&amp;#39;, {
    tags: { type: &amp;#39;API&amp;#39; },
  });
  const res2 = http.get(&amp;#39;https://quickpizza.grafana.com/api/json&amp;#39;, {
    tags: { type: &amp;#39;API&amp;#39; },
  });

  const responses = http.batch([
    [
      &amp;#39;GET&amp;#39;,
      &amp;#39;https://quickpizza.grafana.com/favicon.ico&amp;#39;,
      null,
      { tags: { type: &amp;#39;staticContent&amp;#39; } },
    ],
    [&amp;#39;GET&amp;#39;, &amp;#39;https://quickpizza.grafana.com/admin&amp;#39;, null, { tags: { type: &amp;#39;staticContent&amp;#39; } }],
  ]);

  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;When you 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/#load-options-and-thresholds&#34;&gt;select scenarios with &lt;code&gt;--scenario&lt;/code&gt;&lt;/a&gt;, k6 removes thresholds tagged for configured scenarios you exclude and logs a warning. Those thresholds stay skipped even if a selected scenario emits samples with the excluded scenario&amp;rsquo;s tag. Global thresholds and other tag filters remain active.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;abort-a-test-when-a-threshold-is-crossed&#34;&gt;Abort a test when a threshold is crossed&lt;/h2&gt;
&lt;p&gt;If you want to abort a test as soon as a threshold is crossed,
set the &lt;code&gt;abortOnFail&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;.
When you set &lt;code&gt;abortOnFail&lt;/code&gt;, the test run stops &lt;em&gt;as soon as the threshold fails&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Sometimes, though, a test might fail a threshold early and abort before the test generates significant data.
To prevent these cases, you can delay &lt;code&gt;abortOnFail&lt;/code&gt; with &lt;code&gt;delayAbortEval&lt;/code&gt;.
In this script, &lt;code&gt;abortOnFail&lt;/code&gt; is delayed ten seconds.
After ten seconds, the test aborts if it fails the &lt;code&gt;p(99) &amp;lt; 10&lt;/code&gt; threshold.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    metric_name: [
      {
        threshold: &amp;#39;p(99) &amp;lt; 10&amp;#39;, // string
        abortOnFail: true, // boolean
        delayAbortEval: &amp;#39;10s&amp;#39;, // string
        /*...*/
      },
    ],
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The fields are as follows:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Name&lt;/th&gt;
              &lt;th&gt;Type&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;threshold&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;This is the threshold expression string specifying the threshold condition to evaluate.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;abortOnFail&lt;/td&gt;
              &lt;td&gt;boolean&lt;/td&gt;
              &lt;td&gt;Whether to abort the test if the threshold is evaluated to false before the test has completed.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;delayAbortEval&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;If you want to delay the evaluation of the threshold to let some metric samples to be collected, you can specify the amount of time to delay using relative time strings like &lt;code&gt;10s&lt;/code&gt;, &lt;code&gt;1m&lt;/code&gt; and so on.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;Here is an example:&lt;/p&gt;
&lt;!-- md-k6:nothresholds --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export const options = {
  vus: 30,
  duration: &amp;#39;2m&amp;#39;,
  thresholds: {
    http_req_duration: [{ threshold: &amp;#39;p(99) &amp;lt; 10&amp;#39;, abortOnFail: true }],
  },
};

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;admonition admonition-caution&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Caution&lt;/p&gt;&lt;p&gt;When k6 runs in the cloud, thresholds are evaluated every 60 seconds.
Therefore, the &lt;code&gt;abortOnFail&lt;/code&gt; feature may be delayed by up to 60 seconds.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;fail-a-load-test-using-checks&#34;&gt;Fail a load test using checks&lt;/h2&gt;
&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;Checks&lt;/a&gt; are nice for codifying assertions, but unlike &lt;code&gt;thresholds&lt;/code&gt;, &lt;code&gt;checks&lt;/code&gt; do not affect the exit status of k6.&lt;/p&gt;
&lt;p&gt;If you use only &lt;code&gt;checks&lt;/code&gt; to verify that things work as expected, you can&amp;rsquo;t fail the whole test run based on the &lt;code&gt;check&lt;/code&gt; results.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s often useful to combine &lt;code&gt;checks&lt;/code&gt; and &lt;code&gt;thresholds&lt;/code&gt;, to get the best of both:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check, sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  vus: 50,
  duration: &amp;#39;10s&amp;#39;,
  thresholds: {
    // the rate of successful checks should be higher than 90%
    checks: [&amp;#39;rate&amp;gt;0.9&amp;#39;],
  },
};

export default function () {
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/status/500&amp;#39;);

  check(res, {
    &amp;#39;status is 500&amp;#39;: (r) =&amp;gt; r.status == 500,
  });

  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In this example, the &lt;code&gt;threshold&lt;/code&gt; is configured on the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/reference/&#34;&gt;checks metric&lt;/a&gt;, establishing that the rate of successful checks is higher than 90%.&lt;/p&gt;
&lt;p&gt;Additionally, you can use &lt;code&gt;tags&lt;/code&gt; on checks if you want to define a threshold based on a particular check or group of checks. For example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check, sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  vus: 50,
  duration: &amp;#39;10s&amp;#39;,
  thresholds: {
    &amp;#39;checks{myTag:hola}&amp;#39;: [&amp;#39;rate&amp;gt;0.9&amp;#39;],
  },
};

export default function () {
  let res;

  res = http.get(&amp;#39;https://quickpizza.grafana.com/api/status/500&amp;#39;);
  check(res, {
    &amp;#39;status is 500&amp;#39;: (r) =&amp;gt; r.status == 500,
  });

  res = http.get(&amp;#39;https://quickpizza.grafana.com/api/status/200&amp;#39;);
  check(
    res,
    {
      &amp;#39;status is 200&amp;#39;: (r) =&amp;gt; r.status == 200,
    },
    { myTag: &amp;#39;hola&amp;#39; }
  );

  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="thresholds">Thresholds&lt;/h1>
&lt;p>Thresholds are the pass/fail criteria that you define for your test metrics.
If the performance of the system under test (SUT) does not meet the conditions of your threshold,
&lt;strong>the test finishes with a failed status.&lt;/strong>&lt;/p></description></item><item><title>Options</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/k6-options/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/k6-options/</guid><content><![CDATA[&lt;h1 id=&#34;options&#34;&gt;Options&lt;/h1&gt;
&lt;p&gt;Options configure test-run behavior.
For example, options are how you define test tags, thresholds, user agents, and the number of virtual users and iterations.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;On this page&lt;/th&gt;
              &lt;th&gt;Read about&amp;hellip;&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/&#34;&gt;How to use options&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;How to set options in different places (with examples), how to override options, and how to access the value of an option as the test runs.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/&#34;&gt;Options reference&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;Every option, with examples, defaults, and descriptions.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;]]></content><description>&lt;h1 id="options">Options&lt;/h1>
&lt;p>Options configure test-run behavior.
For example, options are how you define test tags, thresholds, user agents, and the number of virtual users and iterations.&lt;/p></description></item><item><title>Test lifecycle</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/test-lifecycle/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/test-lifecycle/</guid><content><![CDATA[&lt;h1 id=&#34;test-lifecycle&#34;&gt;Test lifecycle&lt;/h1&gt;
&lt;p&gt;In the lifecycle of a k6 test,
a script always runs through these stages in the same order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Code in the &lt;code&gt;init&lt;/code&gt; context prepares the script, loading files, importing modules, and defining the test &lt;em&gt;lifecycle functions&lt;/em&gt;. &lt;strong&gt;Required&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;setup&lt;/code&gt; function runs, setting up the test environment and generating data. &lt;em&gt;Optional.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;VU code runs in the &lt;code&gt;default&lt;/code&gt; or scenario function, running for as long and as many times as the &lt;code&gt;options&lt;/code&gt; define. &lt;strong&gt;Required&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;teardown&lt;/code&gt; function runs, postprocessing data and closing the test environment. &lt;em&gt;Optional.&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Lifecycle functions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Except for init code, each stage occurs in a &lt;em&gt;lifecycle function&lt;/em&gt;,
a function called in a specific sequence in the k6 runtime.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// 1. init code

export function setup() {
  // 2. setup code
}

export default function (data) {
  // 3. VU code
}

export function teardown(data) {
  // 4. teardown code
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;overview-of-the-lifecycle-stages&#34;&gt;Overview of the lifecycle stages&lt;/h2&gt;
&lt;p&gt;For examples and implementation details of each stage, refer to the subsequent sections.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Test stage&lt;/th&gt;
              &lt;th&gt;Purpose&lt;/th&gt;
              &lt;th&gt;Example&lt;/th&gt;
              &lt;th&gt;Called&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;1. init&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Load local files, import modules, declare lifecycle functions&lt;/td&gt;
              &lt;td&gt;Open JSON file, Import module&lt;/td&gt;
              &lt;td&gt;Once per VU*&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;2. Setup&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Set up data for processing, share data among VUs&lt;/td&gt;
              &lt;td&gt;Call API to start test environment&lt;/td&gt;
              &lt;td&gt;Once&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;3. VU code&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Run the test function, usually &lt;code&gt;default&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Make https requests, validate responses&lt;/td&gt;
              &lt;td&gt;Once per iteration, as many times as the test options require&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;4. Teardown&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Process result of setup code, stop test environment&lt;/td&gt;
              &lt;td&gt;Validate that setup had a certain result, send webhook notifying that test has finished&lt;/td&gt;
              &lt;td&gt;Once **&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;* In cloud scripts, init code might be called more often.&lt;/p&gt;
&lt;p&gt;** If the &lt;code&gt;Setup&lt;/code&gt; function ends abnormally (e.g throws an error), the &lt;code&gt;teardown()&lt;/code&gt; function isn&amp;rsquo;t called. Consider adding logic to the &lt;code&gt;setup()&lt;/code&gt; function to handle errors and ensure proper cleanup.&lt;/p&gt;
&lt;h2 id=&#34;the-init-stage&#34;&gt;The init stage&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The init stage is required&lt;/strong&gt;.
Before the test runs, k6 needs to initialize the test conditions.
To prepare the test, code in the &lt;code&gt;init&lt;/code&gt; context runs once per VU.&lt;/p&gt;
&lt;p&gt;Some operations that might happen in &lt;code&gt;init&lt;/code&gt; include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import modules&lt;/li&gt;
&lt;li&gt;Load files from the local file system&lt;/li&gt;
&lt;li&gt;Configure the test for all &lt;code&gt;options&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Define lifecycle functions for the VU, &lt;code&gt;setup&lt;/code&gt;, and &lt;code&gt;teardown&lt;/code&gt; stages (and for custom or &lt;code&gt;handleSummary()&lt;/code&gt; functions, too).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;All code that is outside of a lifecycle function is code in the &lt;code&gt;init&lt;/code&gt; context&lt;/strong&gt;.
Code in the &lt;code&gt;init&lt;/code&gt; context &lt;em&gt;always executes first&lt;/em&gt;.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// init context: importing modules
import http from &amp;#39;k6/http&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;

// init context: define k6 options
export const options = {
  vus: 10,
  duration: &amp;#39;30s&amp;#39;,
};

// init context: global variables
const customTrend = new Trend(&amp;#39;oneCustomMetric&amp;#39;);

// init context: define custom function
function myCustomFunction() {
  // ...
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Separating the &lt;code&gt;init&lt;/code&gt; stage from the VU stage removes irrelevant computation from VU code, which improves k6 performance and makes test results more reliable.
One limitation of &lt;code&gt;init&lt;/code&gt; code is that it &lt;strong&gt;cannot&lt;/strong&gt; make HTTP requests.
This limitation ensures that the &lt;code&gt;init&lt;/code&gt; stage is reproducible across tests (the response from protocol requests is dynamic and unpredictable)&lt;/p&gt;
&lt;h2 id=&#34;the-vu-stage&#34;&gt;The VU stage&lt;/h2&gt;
&lt;p&gt;Scripts must contain, at least, a &lt;em&gt;scenario function&lt;/em&gt; that defines the logic of the VUs.
The code inside this function is &lt;em&gt;VU code&lt;/em&gt;.
Typically, VU code is inside the &lt;code&gt;default&lt;/code&gt; function, but it can also be inside the function defined by a scenario (see subsequent section for an example).&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export default function () {
  // do things here...
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VU code runs over and over through the test duration.&lt;/strong&gt;
VU code can make HTTP requests, emit metrics, and generally do everything you&amp;rsquo;d expect a load test to do.
The only exceptions are the jobs that happen in the &lt;code&gt;init&lt;/code&gt; context.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VU code &lt;em&gt;does not&lt;/em&gt; load files from your local filesystem.&lt;/li&gt;
&lt;li&gt;VU code &lt;em&gt;does not&lt;/em&gt; import any other modules.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Again, instead of VU code, init code does these jobs.&lt;/p&gt;
&lt;h3 id=&#34;the-default-function-life-cycle&#34;&gt;The default function life-cycle&lt;/h3&gt;
&lt;p&gt;A VU executes the &lt;code&gt;default()&lt;/code&gt; function from start to end in sequence.
Once the VU reaches the end of the function, it loops back to the start and executes the code all over.&lt;/p&gt;
&lt;p&gt;As part of this &amp;ldquo;restart&amp;rdquo; process, k6 resets the VU.
Cookies are cleared, and TCP connections might be torn down (depending on your test configuration options).&lt;/p&gt;
&lt;h2 id=&#34;setup-and-teardown-stages&#34;&gt;Setup and teardown stages&lt;/h2&gt;
&lt;p&gt;Like &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt; functions must be exported functions.
But unlike the &lt;code&gt;default&lt;/code&gt; function, k6 calls &lt;code&gt;setup&lt;/code&gt; and &lt;code&gt;teardown&lt;/code&gt; only once per test.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setup&lt;/code&gt; is called at the beginning of the test, after the init stage but before the VU stage.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;teardown&lt;/code&gt; is called at the end of a test, after the VU stage (&lt;code&gt;default&lt;/code&gt; function).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can call the full k6 API in the setup and teardown stages, unlike the init stage.
For example, you can make HTTP requests:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export function setup() {
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/json&amp;#39;);
  return { data: res.json() };
}

export function teardown(data) {
  console.log(JSON.stringify(data));
}

export default function (data) {
  console.log(JSON.stringify(data));
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;setup()&lt;/code&gt; function must complete within the configured 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#setup-timeout&#34;&gt;&lt;code&gt;setupTimeout&lt;/code&gt;&lt;/a&gt; (default: 60 seconds). If it exceeds this timeout, the test fails before any VUs start.&lt;/p&gt;
&lt;p&gt;In Grafana Cloud k6, &lt;code&gt;setupTimeout&lt;/code&gt; has a maximum limit of 10 minutes. If your &lt;code&gt;setup()&lt;/code&gt; function requires long-running operations, consider moving heavy work to an external process and passing the results to your test.&lt;/p&gt;
&lt;h3 id=&#34;skip-setup-and-teardown-execution&#34;&gt;Skip setup and teardown execution&lt;/h3&gt;
&lt;p&gt;You can skip the execution of setup and teardown stages using the options &lt;code&gt;--no-setup&lt;/code&gt; and
&lt;code&gt;--no-teardown&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --no-setup --no-teardown ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;use-data-from-setup-in-default-and-teardown&#34;&gt;Use data from setup in default and teardown&lt;/h3&gt;
&lt;p&gt;Again, let&amp;rsquo;s have a look at the basic structure of a k6 test:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// 1. init code

export function setup() {
  // 2. setup code
}

export default function (data) {
  // 3. VU code
}

export function teardown(data) {
  // 4. teardown code
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You might have noticed the function signatures of the &lt;code&gt;default()&lt;/code&gt; and &lt;code&gt;teardown()&lt;/code&gt; functions take an argument, referred to here as &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of passing some data from the setup code to the VU and teardown stages:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export function setup() {
  return { v: 1 };
}

export default function (data) {
  console.log(JSON.stringify(data));
}

export function teardown(data) {
  if (data.v != 1) {
    throw new Error(&amp;#39;incorrect data: &amp;#39; &amp;#43; JSON.stringify(data));
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For example, with the data returned by the &lt;code&gt;setup()&lt;/code&gt; function, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Give each VU access to an identical copy of the data&lt;/li&gt;
&lt;li&gt;Postprocess the data in &lt;code&gt;teardown&lt;/code&gt; code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, there are some restrictions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can pass only data (i.e. JSON) between &lt;code&gt;setup&lt;/code&gt; and the other stages.
You cannot pass functions.&lt;/li&gt;
&lt;li&gt;If the data returned by the &lt;code&gt;setup()&lt;/code&gt; function is large, it will consume more memory.&lt;/li&gt;
&lt;li&gt;You cannot manipulate data in the &lt;code&gt;default()&lt;/code&gt; function, then pass it to the &lt;code&gt;teardown()&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s best to think that each stage and each VU has access to a fresh &amp;ldquo;copy&amp;rdquo; of whatever data the &lt;code&gt;setup()&lt;/code&gt; function returns.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;/media/docs/k6-oss/lifecycle.png&#34;
  alt=&#34;Diagram showing data getting returned by setup, then used (separately) by default and teardown functions&#34; width=&#34;291&#34;
     height=&#34;321&#34;/&gt;&lt;/p&gt;
&lt;p&gt;It would be extremely complicated and computationally intensive to pass mutable data between all VUs and then to teardown, especially in distributed setups.
This would go against a core k6 goal: the same script should be executable in multiple modes.&lt;/p&gt;
&lt;h2 id=&#34;additional-lifecycle-functions&#34;&gt;Additional lifecycle functions&lt;/h2&gt;
&lt;p&gt;k6 has a few additional ways to use lifecycle functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;handleSummary()&lt;/code&gt;&lt;/strong&gt;. If you want to make a custom summary, k6 calls one more lifecycle function at the very end of the test.&lt;/p&gt;
&lt;p&gt;For details, refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/end-of-test/custom-summary/&#34;&gt;Custom summary&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scenario functions&lt;/strong&gt;. Instead of the &lt;code&gt;default&lt;/code&gt; function, you can also run VU code in scenario functions.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export const options = {
  scenarios: {
    my_web_test: {
      // the function this scenario will execute
      exec: &amp;#39;webtest&amp;#39;,
      executor: &amp;#39;constant-vus&amp;#39;,
      vus: 50,
      duration: &amp;#39;1m&amp;#39;,
    },
  },
};

export function webtest() {
  http.get(&amp;#39;https://test.k6.io/contacts.php&amp;#39;);
  sleep(Math.random() * 2);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="test-lifecycle">Test lifecycle&lt;/h1>
&lt;p>In the lifecycle of a k6 test,
a script always runs through these stages in the same order:&lt;/p>
&lt;ol>
&lt;li>Code in the &lt;code>init&lt;/code> context prepares the script, loading files, importing modules, and defining the test &lt;em>lifecycle functions&lt;/em>. &lt;strong>Required&lt;/strong>.&lt;/li>
&lt;li>The &lt;code>setup&lt;/code> function runs, setting up the test environment and generating data. &lt;em>Optional.&lt;/em>&lt;/li>
&lt;li>VU code runs in the &lt;code>default&lt;/code> or scenario function, running for as long and as many times as the &lt;code>options&lt;/code> define. &lt;strong>Required&lt;/strong>.&lt;/li>
&lt;li>The &lt;code>teardown&lt;/code> function runs, postprocessing data and closing the test environment. &lt;em>Optional.&lt;/em>&lt;/li>
&lt;/ol>
&lt;div class="admonition admonition-note">&lt;blockquote>&lt;p class="title text-uppercase">Note&lt;/p></description></item><item><title>Modules</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/modules/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/modules/</guid><content><![CDATA[&lt;h1 id=&#34;modules&#34;&gt;Modules&lt;/h1&gt;
&lt;h2 id=&#34;import-modules&#34;&gt;Import modules&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s common to import modules, or parts of modules, to use in your test scripts.
In k6, you can import different kinds of modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#built-in-modules&#34;&gt;Built-in modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#local-modules&#34;&gt;Local modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#remote-modules&#34;&gt;Remote modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#extension-modules&#34;&gt;Extension modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;built-in-modules&#34;&gt;Built-in modules&lt;/h3&gt;
&lt;p&gt;k6 provides many built-in modules for core functionalities.
For example, the &lt;code&gt;http&lt;/code&gt; client make requests against the
system under test.
For the full list of built-in modules, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/&#34;&gt;API documentation&lt;/a&gt;.&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;local-modules&#34;&gt;Local modules&lt;/h3&gt;
&lt;p&gt;These modules are stored on the local filesystem, and accessed either through relative or absolute filesystem paths.&lt;/p&gt;
&lt;p&gt;k6 adopts a &lt;strong&gt;browser-like module resolution&lt;/strong&gt; and doesn&amp;rsquo;t support &lt;a href=&#34;https://nodejs.org/api/modules.html#modules_all_together&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Node.js module resolution&lt;/a&gt;. File names for &lt;code&gt;imports&lt;/code&gt; must be fully specified, such as &lt;code&gt;./helpers.js&lt;/code&gt;.&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;//my-test.js
import { someHelper } from &amp;#39;./helpers.js&amp;#39;;

export default function () {
  someHelper();
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;//helpers.js
export function someHelper() {
  // ...
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;remote-modules&#34;&gt;Remote modules&lt;/h3&gt;
&lt;p&gt;These modules are accessed over HTTP(S), from a public source like GitHub, any CDN, or
from any publicly accessible web server. The imported modules are downloaded and executed at
runtime, making it extremely important to &lt;strong&gt;make sure you trust the code before including
it in a test script&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example, 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/&#34;&gt;jslib&lt;/a&gt; is a set of k6 JavaScript libraries available as remote HTTPS modules. They can be downloaded and imported as local modules or directly imported as remote modules.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { randomItem } from &amp;#39;https://jslib.k6.io/k6-utils/1.2.0/index.js&amp;#39;;

export default function () {
  randomItem([1, 2, 3]);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also build your custom Javascript libraries and distribute them via a public web hosting. For reference, &lt;a href=&#34;https://github.com/grafana/k6-jslib-aws&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-jslib-aws&lt;/a&gt; and &lt;a href=&#34;https://github.com/grafana/k6-rollup-example&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-rollup-example&lt;/a&gt; host their modules as GitHub release assets.&lt;/p&gt;
&lt;h3 id=&#34;extension-modules&#34;&gt;Extension modules&lt;/h3&gt;
&lt;p&gt;Like the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/&#34;&gt;k6 APIs&lt;/a&gt;, you can build custom modules in Go code and expose them as JavaScript modules. These custom Go-to-JS modules are known as 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/&#34;&gt;k6 extensions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Below is an example that imports the &lt;code&gt;k6/x/kubernetes&lt;/code&gt; module from the &lt;a href=&#34;https://github.com/grafana/xk6-kubernetes&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;xk6-kubernetes&lt;/a&gt; extension.&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { Kubernetes } from &amp;#39;k6/x/kubernetes&amp;#39;;

const podSpec = {
  apiVersion: &amp;#39;v1&amp;#39;,
  kind: &amp;#39;Pod&amp;#39;,
  metadata: { name: &amp;#39;busybox&amp;#39;, namespace: &amp;#39;testns&amp;#39; },
  spec: {
    containers: [
      {
        name: &amp;#39;busybox&amp;#39;,
        image: &amp;#39;busybox&amp;#39;,
        command: [&amp;#39;sh&amp;#39;, &amp;#39;-c&amp;#39;, &amp;#39;sleep 30&amp;#39;],
      },
    ],
  },
};
export default function () {
  const kubernetes = new Kubernetes();
  kubernetes.create(podSpec);
  const pods = kubernetes.list(&amp;#39;Pod&amp;#39;, &amp;#39;testns&amp;#39;);
  pods.map(function (pod) {
    console.log(pod.metadata.name);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;How do k6 extensions (Go-to-JS modules) work? For enhanced performance, the k6 engine is written in Go and embeds a JavaScript VM (&lt;a href=&#34;https://github.com/grafana/sobek&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;sobek&lt;/a&gt;) to execute JavaScript test code. That allows you to build your modules in Go code and import them as JavaScript as usual.&lt;/p&gt;
&lt;p&gt;To learn more about using or creating k6 extensions, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/&#34;&gt;Extension documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;share-javascript-modules&#34;&gt;Share JavaScript modules&lt;/h2&gt;
&lt;p&gt;As mentioned previously, users can import custom JavaScript libraries by loading either local or remote modules. Because of that, we have two options to import JavaScript modules, along with various methods to distribute them.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;The following options for distributing and sharing JavaScript libraries are available for both custom and other public libraries.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;remote-modules-1&#34;&gt;Remote modules&lt;/h3&gt;
&lt;p&gt;You can host your modules in a public webserver like GitHub and any CDN and be imported remotely.&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// As GitHub release assets
import {
  WorkloadConfig,
  sayHello,
} from &amp;#39;https://github.com/grafana/k6-rollup-example/releases/download/v0.0.2/index.js&amp;#39;;

// or hosted in a CDN
import { randomIntBetween, randomItem } from &amp;#39;https://jslib.k6.io/k6-utils/1.4.0/index.js&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When the library consists of multiple files and modules, you may want to bundle these modules to create public releases. Here are some examples for reference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using Webpack: &lt;a href=&#34;https://github.com/grafana/k6-jslib-utils&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-jslib-utils&lt;/a&gt; and &lt;a href=&#34;https://github.com/grafana/k6-jslib-aws&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-jslib-aws&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using Rollup: &lt;a href=&#34;https://github.com/grafana/k6-rollup-example/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;test-commons&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Be aware that k6 automatically executes remote modules, making it crucial to trust the source code of these remote modules. There is a &lt;strong&gt;risk of altering the remote modules with certain hosting mechanisms&lt;/strong&gt;. To mitigate this security risk, some users prefer to download and import the modules locally to ensure full control of the source code.&lt;/p&gt;
&lt;h3 id=&#34;local-modules-1&#34;&gt;Local modules&lt;/h3&gt;
&lt;p&gt;In this example, the previous remote modules have been downloaded to the &lt;code&gt;lib&lt;/code&gt; folder of the testing project and imported as follows:&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { WorkloadConfig, sayHello } from &amp;#39;./libs/test-commons.js&amp;#39;;

import { randomIntBetween, randomItem } from &amp;#39;./libs/k6-utils.js&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Another option to distribute libraries is to use a package manager tool like npm, which enables version locking and the linking of local libraries. The latter can be useful during development.&lt;/p&gt;
&lt;p&gt;Although k6 does not resolve node modules, you can utilize a Bundler to load npm dependencies, as shown in the &lt;a href=&#34;https://github.com/grafana/k6-rollup-example&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-rollup-example&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;use-nodejs-modules&#34;&gt;Use Node.js modules&lt;/h2&gt;


&lt;div class=&#34;admonition admonition-caution&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Caution&lt;/p&gt;&lt;p&gt;k6 isn&amp;rsquo;t Node.js or a browser. Packages that rely on APIs provided by Node.js, for instance the &lt;code&gt;os&lt;/code&gt; and &lt;code&gt;fs&lt;/code&gt; modules, won&amp;rsquo;t work in k6. The same goes for browser-specific APIs, such as the &lt;code&gt;window&lt;/code&gt; object.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;In a JavaScript project running Node.js, modules are imported using either &lt;code&gt;import&lt;/code&gt; or &lt;code&gt;require()&lt;/code&gt;, using the Node.js module resolution algorithm. This means that a user can import modules by name, without providing the full filesystem path to the module. For instance:&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { ClassInAModule } from &amp;#39;cool-module&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;import&lt;/code&gt; statement would be automatically resolved by the node resolution algorithm by searching:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The current directory&lt;/li&gt;
&lt;li&gt;Any &lt;code&gt;node_modules&lt;/code&gt; folder in the directory&lt;/li&gt;
&lt;li&gt;Any &lt;code&gt;node_modules&lt;/code&gt; folder in a parent directory, up to the closest &lt;code&gt;package.json&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the implementation of &lt;code&gt;import&lt;/code&gt; in k6 lacks support for the node module resolution algorithm, Node.js modules that resolve external dependencies need to be transformed into a self-contained, isolated, bundle.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s done with the help of a bundling tool, such as Webpack, which analyses the test script, identifies all external dependencies, and then creates a self-contained bundle including everything necessary to run the script.&lt;/p&gt;
&lt;p&gt;If the test script has no external dependencies, already has them vendored in a k6 compatible way, or only uses ES5.1&#43; features, using a bundler isn&amp;rsquo;t necessary.&lt;/p&gt;
&lt;h3 id=&#34;pick-a-bundler&#34;&gt;Pick a bundler&lt;/h3&gt;
&lt;p&gt;You can use any bundler that supports transpilation. Popular ones include, but are not limited to, &lt;a href=&#34;https://github.com/webpack/webpack&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;webpack&lt;/a&gt;, &lt;a href=&#34;https://github.com/parcel-bundler/parcel&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;parcel&lt;/a&gt;, &lt;a href=&#34;https://github.com/rollup/rollup&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;rollup&lt;/a&gt; and &lt;a href=&#34;https://github.com/browserify/browserify&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;browserify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Due to its flexibility, ease of use, relatively low resource consumption, and known compatibility with k6, it is recommended to use &lt;a href=&#34;https://github.com/webpack/webpack&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;webpack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also use these two example repositories as a starting point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-template-es6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-template-es6&lt;/a&gt;: Template using Webpack and Babel to enable ES6 features in k6 tests.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-rollup-example/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-rollup-example&lt;/a&gt;: Example using Rollup to bundle k6 tests and release a shared library.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;webpack-setup-example&#34;&gt;Webpack setup example&lt;/h3&gt;
&lt;p&gt;Setting up a Babel and Webpack project from scratch might sound like a big undertaking, but
is usually accomplished within minutes. Start by creating a project folder and initializing
&lt;code&gt;npm&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;mkdir ./example-project &amp;amp;&amp;amp; \
    cd &amp;#34;$_&amp;#34; &amp;amp;&amp;amp; \
    npm init -y&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h4 id=&#34;install-packages&#34;&gt;Install packages&lt;/h4&gt;
&lt;p&gt;Then, install the packages needed:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;npm install --save-dev \
    webpack \
    webpack-cli \
    @types/k6 \
    babel-loader \
    @babel/core \
    @babel/preset-env \
    core-js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th style=&#34;text-align: left&#34;&gt;Package&lt;/th&gt;
              &lt;th style=&#34;text-align: left&#34;&gt;Usage&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/webpack/webpack&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;webpack&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;The bundler part of Webpack&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/webpack/webpack-cli&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;webpack-cli&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;The CLI part of Webpack, which allows us to use it from the terminal&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/k6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;@types/k6&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;k6 Typescript definition&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/babel/babel-loader&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;babel-loader&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;A loader used by Webpack to leverage babel functionality while bundling&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/babel/babel/tree/master/packages/babel-core&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;@babel/core&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;The core functionality of Babel&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/babel/babel/tree/master/packages/babel-preset-env&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;@babel/preset-env&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;A smart preset using &lt;a href=&#34;https://github.com/browserslist/browserslist&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;browserlist&lt;/a&gt;, &lt;a href=&#34;https://github.com/kangax/compat-table&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;compat-table&lt;/a&gt; and &lt;a href=&#34;https://github.com/Kilian/electron-to-chromium&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;electron-to-chromium&lt;/a&gt; to determine what code to transpile and polyfill.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;&lt;a href=&#34;https://github.com/zloirock/core-js&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;core-js&lt;/a&gt;&lt;/td&gt;
              &lt;td style=&#34;text-align: left&#34;&gt;A modular standard library for JS including polyfills&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h4 id=&#34;configure-webpack&#34;&gt;Configure Webpack&lt;/h4&gt;
&lt;p&gt;Once these packages have been added, the next step will be to set up a &lt;code&gt;webpack.config.js&lt;/code&gt; file:&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;const path = require(&amp;#39;path&amp;#39;);

module.exports = {
  mode: &amp;#39;production&amp;#39;,
  entry: {
    login: &amp;#39;./src/login.test.js&amp;#39;,
    signup: &amp;#39;./src/signup.test.js&amp;#39;,
  },
  output: {
    path: path.resolve(__dirname, &amp;#39;dist&amp;#39;), // eslint-disable-line
    libraryTarget: &amp;#39;commonjs&amp;#39;,
    filename: &amp;#39;[name].bundle.js&amp;#39;,
  },
  module: {
    rules: [{ test: /\.js$/, use: &amp;#39;babel-loader&amp;#39; }],
  },
  target: &amp;#39;web&amp;#39;,
  externals: /k6(\/.*)?/,
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Mode&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Tells Webpack to automatically use the optimizations associated with the &lt;code&gt;mode&lt;/code&gt;.
Additional details available in &lt;a href=&#34;https://webpack.js.org/configuration/mode/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;the webpack docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Entry&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The files Webpack will use as its entry points while performing the bundling. From these points,
Webpack will automatically traverse all imports recursively until every possible dependency path has
been exhausted. For instance:&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// login.test.js

import { SomeService } from &amp;#39;./some.service.js&amp;#39;;

const svc = new SomeService();&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// some.service.js

import * as lodash from &amp;#39;lodash&amp;#39;;

export class SomeService {
  constructor() {
    this._ = lodash;
  }
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;would result in Webpack bundling &lt;code&gt;login.test.js&lt;/code&gt;, &lt;code&gt;some.service.js&lt;/code&gt; and all upstream dependencies
utilized by &lt;code&gt;lodash&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Output&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;path&lt;/code&gt; key takes an absolute path which is where the finished bundle will be placed. In
this example, &lt;code&gt;path.resolve&lt;/code&gt; is used to concatenate &lt;code&gt;__dirname&lt;/code&gt; and &lt;code&gt;&#39;dist&#39;&lt;/code&gt; into an absolute
path.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;libraryTarget&lt;/code&gt; key configures how the library will be exposed. Setting it to &lt;code&gt;commonjs&lt;/code&gt;
will result in it being exported using &lt;code&gt;module.exports&lt;/code&gt;. Additional details available in &lt;a href=&#34;https://webpack.js.org/configuration/output/#outputlibrarytarget&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;the
Webpack docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;filename&lt;/code&gt; key, as the name suggests, configures the name of the finished bundles. In this
example, the &lt;a href=&#34;https://webpack.js.org/configuration/output/#template-strings&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;template string&lt;/a&gt; &lt;code&gt;[name]&lt;/code&gt;
is used to add a dynamic part to the output filename.&lt;/p&gt;
&lt;h4 id=&#34;add-a-bundle-command&#34;&gt;Add a bundle command&lt;/h4&gt;
&lt;p&gt;Open the &lt;code&gt;package.json&lt;/code&gt; file and add a new script entry, used for running the bundling process.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;diff&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-diff&#34;&gt;{
  &amp;#34;name&amp;#34;: &amp;#34;bundling-example&amp;#34;,
  &amp;#34;description&amp;#34;: &amp;#34;&amp;#34;,
  &amp;#34;version&amp;#34;: &amp;#34;0.1.0&amp;#34;,
  &amp;#34;private&amp;#34;: true,
  &amp;#34;scripts&amp;#34;: {
&amp;#43;    &amp;#34;bundle&amp;#34;: &amp;#34;webpack&amp;#34;
  }
  ...
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h4 id=&#34;bundle-tests&#34;&gt;Bundle tests&lt;/h4&gt;
&lt;p&gt;Running webpack will now output two different test bundles, that may be executed independently:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ npm run bundle
# ...
$ tree dist

dist
├── login.bundle.js
└── signup.bundle.js

0 directories, 2 files&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h4 id=&#34;run-tests&#34;&gt;Run tests&lt;/h4&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ npm run bundle
# ...
$ k6 run dist/login.bundle.js
# ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ npm run bundle
# ...
$ k6 run dist/signup.bundle.js \
    --vus 10 \
    --duration 10s
# ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;use-typescript&#34;&gt;Use TypeScript&lt;/h2&gt;
&lt;p&gt;k6 supports partial TypeScript support. For more details, refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/javascript-typescript-compatibility-mode/&#34;&gt;JavaScript and TypeScript compatibility mode&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;use-modules-with-docker&#34;&gt;Use modules with Docker&lt;/h2&gt;
&lt;p&gt;Built-in and remote modules work out of the box when running k6 in a Docker container like the &lt;a href=&#34;https://hub.docker.com/r/grafana/k6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Grafana k6 Docker image&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;local-modules-2&#34;&gt;Local modules&lt;/h3&gt;
&lt;p&gt;To run k6 with Docker and import a local module, you must make sure to mount the necessary folders from the host into the container, using &lt;a href=&#34;https://docs.docker.com/engine/admin/volumes/volumes/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Docker volumes&lt;/a&gt;. Thus, k6 can see all the JS modules it needs to import.&lt;/p&gt;
&lt;p&gt;For example, say you have the following structure on your host machine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/home/k6/example/src/index.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/home/k6/example/src/modules/module.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { hello_world } from &amp;#39;./modules/module.js&amp;#39;;

export default function () {
  hello_world();
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!--md-k6:skip--&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export function hello_world() {
  console.log(&amp;#39;Hello world&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To run index.js and make the modules available for import we execute the following Docker command with the &lt;code&gt;/home/k6/example/src&lt;/code&gt; host folder mounted at &lt;code&gt;/src&lt;/code&gt; in the container:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;docker run --rm -v /home/k6/example/src:/src -i grafana/k6 run /src/index.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Note that on Windows, you also need to make sure that your drive in question, say &lt;code&gt;C:\&lt;/code&gt;,
has been marked for sharing in the Docker Desktop settings.&lt;/p&gt;
&lt;h3 id=&#34;extension-modules-1&#34;&gt;Extension modules&lt;/h3&gt;
&lt;p&gt;The official &lt;a href=&#34;https://hub.docker.com/r/grafana/k6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Grafana k6 Docker image&lt;/a&gt; includes the k6 release binary but lacks additional k6 extensions. Therefore, using the official Docker container to run a k6 test that requires an extension will fail.&lt;/p&gt;
&lt;p&gt;To run k6 with extensions in Docker, create a Docker image that includes the k6 binary with any extension you may want to use. Define a &lt;code&gt;Dockerfile&lt;/code&gt; with the necessary 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/build-k6-binary-using-go/#breaking-down-the-xk6-command&#34;&gt;xk6 build&lt;/a&gt; instructions as follows:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;FROM grafana/xk6:latest

RUN GCO_ENABLED=0 xk6 build \
    --with github.com/grafana/xk6-kubernetes@latest

ENTRYPOINT [&amp;#34;./k6&amp;#34;]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After building your custom k6 Docker image, you can 
    &lt;a href=&#34;/docs/k6/v2.3.x/get-started/running-k6/&#34;&gt;run k6 with Docker&lt;/a&gt; as usual.&lt;/p&gt;
&lt;p&gt;Alternatively, you can implement a multistage Dockerfile build such as shown on this &lt;a href=&#34;https://github.com/grafana/xk6-output-prometheus-remote/blob/main/Dockerfile&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Dockerfile example&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2024/04/30/organizing-your-grafana-k6-performance-testing-suite-best-practices-to-get-started/&#34;&gt;Guidelines for organizing your k6 performance testing suite&lt;/a&gt;: Recommendations for large performance testing projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2024/05/02/setting-up-your-grafana-k6-performance-testing-suite-javascript-tools-shared-libraries-and-more/&#34;&gt;JavaScript tools, shared libraries, multiple repos, and central teams&lt;/a&gt;: Options for structuring your performance testing projects and sharing k6 libraries with other teams.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/&#34;&gt;JSLib&lt;/a&gt;: A collection of k6 JavaScript libraries maintained by Grafana Labs and available as remote modules.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/explore/&#34;&gt;Extensions directory&lt;/a&gt;: A collection of k6 extensions maintained by Grafana Labs and the community.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-rollup-example&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-rollup-example&lt;/a&gt;: Example using Rollup and Babel to bundle a common library and testing suite.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-template-es6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-template-es6&lt;/a&gt;: Template using Webpack and Babel to bundle k6 tests into CommonJS modules and polyfill ES&#43; features.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-template-typescript&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-template-typescript&lt;/a&gt;: Template using Webpack and Babel to use TypeScript in your k6 scripts.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/javascript-compatibility-mode/&#34;&gt;JavaScript Compatibility Mode&lt;/a&gt;: An option to change the ECMAScript version supported by k6.&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="modules">Modules&lt;/h1>
&lt;h2 id="import-modules">Import modules&lt;/h2>
&lt;p>It&amp;rsquo;s common to import modules, or parts of modules, to use in your test scripts.
In k6, you can import different kinds of modules:&lt;/p></description></item><item><title>Tags and Groups</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/tags-and-groups/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/tags-and-groups/</guid><content><![CDATA[&lt;h1 id=&#34;tags-and-groups&#34;&gt;Tags and Groups&lt;/h1&gt;
&lt;p&gt;A load test usually targets a service with different subsystems and resources.
This can make it hard to pinpoint the issues that are degrading performance.&lt;/p&gt;
&lt;p&gt;To help you visualize, sort, and filter your test results, k6 adds the following to your results.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Tags&lt;/em&gt; categorize your checks, thresholds, custom metrics, and requests for in-depth filtering.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Groups&lt;/em&gt; apply tags to the script&amp;rsquo;s functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides these granular tags, you can also use options to set test-wide tags.
You can use these tags to compare results from multiple tests.&lt;/p&gt;
&lt;p&gt;In addition to filtering results, you can also 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/#thresholds-on-tags&#34;&gt;use tags to limit the operations that your thresholds analyze&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;tags&#34;&gt;Tags&lt;/h2&gt;
&lt;p&gt;Tags are a powerful way to categorize your k6 entities and filter test results.&lt;/p&gt;
&lt;p&gt;k6 provides two types of tags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;System tags.&lt;/strong&gt; Tags that k6 automatically assigns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-defined tags.&lt;/strong&gt; Tags that you add when you write your script.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;system-tags&#34;&gt;System tags&lt;/h3&gt;
&lt;p&gt;Currently, k6 automatically creates the following tags by default:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Tag&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;proto&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the name of the protocol used (e.g. &lt;code&gt;HTTP/1.1&lt;/code&gt;)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;subproto&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the subprotocol name (used by websockets)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the HTTP status code (e.g. &lt;code&gt;200&lt;/code&gt;, &lt;code&gt;404&lt;/code&gt;, etc.)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;method&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the HTTP method name (e.g. &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, etc.) or the RPC method name for gRPC&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;url&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the HTTP request URL&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the HTTP 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/http-requests/#url-grouping&#34;&gt;request name&lt;/a&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;group&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the full &lt;a href=&#34;#groups&#34;&gt;group&lt;/a&gt; path, see the preceding explanation for details about its value&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;check&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;Check&lt;/a&gt; name&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;error&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;a string with a non-HTTP error message (e.g. network or DNS error)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;error_code&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;A number specifying an error types; a list of current error codes can be found at the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/error-codes/&#34;&gt;Error Codes&lt;/a&gt; page&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;tls_version&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/ssl-tls/&#34;&gt;TLS&lt;/a&gt; version&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;scenario&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the name of the scenario where the metric was emitted&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;service&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the RPC service name for gRPC&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;expected_response&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; based on the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/set-response-callback/&#34;&gt;responseCallback&lt;/a&gt;; by default checks whether the status is 2xx or 3xx&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;To disable some of the preceding tags, use the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#system-tags&#34;&gt;&lt;code&gt;systemTags&lt;/code&gt; option&lt;/a&gt;.
Note that some data collectors, for example &lt;code&gt;cloud&lt;/code&gt; runs, may require certain tags.&lt;/p&gt;
&lt;p&gt;The following system tags are optional. Enable them as needed:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Tag&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;vu&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the ID of the virtual user that executed the request&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;iter&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the iteration number&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;ip&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The IP address of the remote server&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;ocsp_status&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/ssl-tls/online-certificate-status-protocol--ocsp/&#34;&gt;Online Certificate Status Protocol (OCSP)&lt;/a&gt; HTTPS status&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;user-defined-tags&#34;&gt;User-defined tags&lt;/h2&gt;
&lt;p&gt;Define your own tags to categorize k6 entities based on your test logic.
You can tag the following entities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;requests&lt;/li&gt;
&lt;li&gt;checks&lt;/li&gt;
&lt;li&gt;thresholds&lt;/li&gt;
&lt;li&gt;custom metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

const myTrend = new Trend(&amp;#39;my_trend&amp;#39;);

export default function () {
  // Add tag to request metric data
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;, {
    tags: {
      my_tag: &amp;#34;I&amp;#39;m a tag&amp;#34;,
    },
  });

  // Add tag to check
  check(res, { &amp;#39;status is 200&amp;#39;: (r) =&amp;gt; r.status === 200 }, { my_tag: &amp;#34;I&amp;#39;m a tag&amp;#34; });

  // Add tag to custom metric
  myTrend.add(res.timings.connecting, { my_tag: &amp;#34;I&amp;#39;m a tag&amp;#34; });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;test-wide-tags&#34;&gt;Test-wide tags&lt;/h2&gt;
&lt;p&gt;Besides attaching tags to requests, checks, and custom metrics, you can set test-wide tags across all metrics.
You can set these tags in four ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In the CLI, using one or more &lt;code&gt;--tag NAME=VALUE&lt;/code&gt; flags&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;code&gt;K6_TAGS&lt;/code&gt; environment variable, using a comma-separated list of &lt;code&gt;NAME:VALUE&lt;/code&gt; pairs:&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Bash&#34;&gt;Bash&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;windows&#34;&gt;windows&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;powershell&#34;&gt;powershell&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;K6_TAGS=name:value,other:value k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;windows&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-windows&#34;&gt;set &amp;#34;K6_TAGS=name:value,other:value&amp;#34; &amp;amp;&amp;amp; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;powershell&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-powershell&#34;&gt;$env:K6_TAGS=&amp;#34;name:value,other:value&amp;#34;; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the script itself:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  tags: {
    name: &amp;#39;value&amp;#39;,
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/#set-options-with-the-config-flag&#34;&gt;JSON config file&lt;/a&gt;, under the &lt;code&gt;tags&lt;/code&gt; key&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;combining-tags-from-multiple-sources&#34;&gt;Combining tags from multiple sources&lt;/h3&gt;
&lt;p&gt;By default, if you set test-wide tags in more than one place, k6 doesn&amp;rsquo;t merge them: whichever source has the highest 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/#order-of-precedence&#34;&gt;order of precedence&lt;/a&gt; replaces the tags from every lower-priority source entirely. For example, if your script sets &lt;code&gt;options.tags = { env: &#39;staging&#39;, team: &#39;backend&#39; }&lt;/code&gt; and you also pass &lt;code&gt;--tag region=us-east&lt;/code&gt;, the result is only &lt;code&gt;{ region: &#39;us-east&#39; }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To merge tags across sources instead of replacing them, enable the &lt;code&gt;merge-run-tags&lt;/code&gt; 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/feature-flags/&#34;&gt;feature flag&lt;/a&gt;. With the flag on, k6 combines the tags from the config file, the script, the environment variable, and the CLI, in that order. On a key collision, the higher-priority source wins.&lt;/p&gt;
&lt;h2 id=&#34;code-defined-tags&#34;&gt;Code-defined tags&lt;/h2&gt;
&lt;p&gt;In the case, a user-defined tag with advanced logic for handling which tag to set is required then it&amp;rsquo;s possible doing it by defining the tag from the code.&lt;/p&gt;
&lt;p&gt;To support advanced tagging workflows, it is also possible to directly set and get them from scripts&amp;rsquo; code.&lt;/p&gt;
&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#vu&#34;&gt;k6/execution.vu.tags&lt;/a&gt; object&amp;rsquo;s properties can indeed be directly assigned new key/value pairs to define new tags dynamically. This can prove useful, as demonstrated in the following example, to track a container&amp;rsquo;s group from nested groups, and aggregating nested group&amp;rsquo;s sub-metrics.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import exec from &amp;#39;k6/execution&amp;#39;;
import { group } from &amp;#39;k6&amp;#39;;

export const options = {
  thresholds: {
    &amp;#39;http_reqs{container_group:main}&amp;#39;: [&amp;#39;count==3&amp;#39;],
    &amp;#39;http_req_duration{container_group:main}&amp;#39;: [&amp;#39;max&amp;lt;1000&amp;#39;],
  },
};

export default function () {
  exec.vu.tags.containerGroup = &amp;#39;main&amp;#39;;

  group(&amp;#39;main&amp;#39;, function () {
    http.get(&amp;#39;https://test.k6.io&amp;#39;);
    group(&amp;#39;sub&amp;#39;, function () {
      http.get(&amp;#39;https://quickpizza.grafana.com/&amp;#39;);
    });
    http.get(&amp;#39;https://quickpizza.grafana.com/api/headers&amp;#39;);
  });

  delete exec.vu.tags.containerGroup;

  http.get(&amp;#39;https://quickpizza.grafana.com/api/delay/3&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Using the same API, you can also retrieve any already set user-defined or system-defined tag:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import exec from &amp;#39;k6/execution&amp;#39;;

export default function () {
  const tag = exec.vu.tags[&amp;#39;scenario&amp;#39;];
  console.log(tag); // default
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;tags-and-metadata-in-asynchronous-code&#34;&gt;Tags and metadata in asynchronous code&lt;/h3&gt;
&lt;p&gt;Metric context is the set of tags and metadata applied to emitted metric samples, including the current &lt;code&gt;group&lt;/code&gt; tag. By default, this context is only reliable in synchronous code. Samples emitted after an asynchronous boundary, such as in an &lt;code&gt;await&lt;/code&gt; continuation, a Promise reaction, or a timer callback, might not keep the context that was active when the asynchronous work started.&lt;/p&gt;
&lt;p&gt;To propagate metric context through asynchronous operations, enable the experimental and opt-in 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/feature-flags/&#34;&gt;&lt;code&gt;async-metric-context&lt;/code&gt; feature flag&lt;/a&gt;. With the feature enabled, k6 captures the current metric context when asynchronous work is registered and applies it when that work runs. It also enables 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/group/&#34;&gt;async callbacks in &lt;code&gt;group()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;tagging-stages&#34;&gt;Tagging stages&lt;/h2&gt;
&lt;p&gt;Thanks to some helper functions in the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/jslib/utils/&#34;&gt;k6-jslib-utils&lt;/a&gt; project, if an executor supports the &lt;code&gt;stages&lt;/code&gt; option, you can add tags with the current ongoing stage.
Similar to other tags tag, the tag is added to all samples collected during the iteration.&lt;/p&gt;
&lt;p&gt;One way to tag the executed operations is to invoke the &lt;code&gt;tagWithCurrentStageIndex&lt;/code&gt; function for setting a &lt;code&gt;stage&lt;/code&gt; tag for identifying the stage that has executed them:&lt;/p&gt;
&lt;!-- md-k6:fixedscenarios --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import exec from &amp;#39;k6/execution&amp;#39;;
import { tagWithCurrentStageIndex } from &amp;#39;https://jslib.k6.io/k6-utils/1.3.0/index.js&amp;#39;;

export const options = {
  stages: [
    { target: 5, duration: &amp;#39;2s&amp;#39; },
    { target: 10, duration: &amp;#39;5s&amp;#39; },
  ],
};

export default function () {
  tagWithCurrentStageIndex();

  // all the requests will have a `stage` tag
  // with its value equal to the index of the stage
  http.get(&amp;#39;https://test.k6.io&amp;#39;); // e.g. {stage: &amp;#34;1&amp;#34;}
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Additionally, a profiling function &lt;code&gt;tagWithCurrentStageProfile&lt;/code&gt; can add a tag with a computed profile of the current running stage:&lt;/p&gt;
&lt;!-- md-k6:fixedscenarios --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import exec from &amp;#39;k6/execution&amp;#39;;
import { tagWithCurrentStageProfile } from &amp;#39;https://jslib.k6.io/k6-utils/1.3.0/index.js&amp;#39;;

export const options = {
  stages: [{ target: 2, duration: &amp;#39;5s&amp;#39; }],
};

export default function () {
  tagWithCurrentStageProfile();

  // all the requests are tagged with a `stage` tag
  // with the index of the stage as value
  http.get(&amp;#39;https://test.k6.io&amp;#39;); // {stage_profile: ramp-up}
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The profile value based on the current stage can be one of the following options:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Profile&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;ramp-up&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The current stage has a target greater than the previous stage&amp;rsquo;s target&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;steady&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The current stage has a target equal to the previous stage&amp;rsquo;s target&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;ramp-down&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;The current stage has a target less than the previous stage&amp;rsquo;s target&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;tags-in-results-output&#34;&gt;Tags in results output&lt;/h2&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;JSON&#34;&gt;JSON&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;JSON&#34;&gt;JSON&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;#34;type &amp;#34;: &amp;#34;Point &amp;#34;,
  &amp;#34;data &amp;#34;: {
    &amp;#34;time &amp;#34;: &amp;#34;2017-05-09T14:34:45.239531499&amp;#43;02:00 &amp;#34;,
    &amp;#34;value &amp;#34;: 459.865729,
    &amp;#34;tags &amp;#34;: {
      &amp;#34;group &amp;#34;: &amp;#34;::my group::json &amp;#34;,
      &amp;#34;method &amp;#34;: &amp;#34;GET &amp;#34;,
      &amp;#34;status &amp;#34;: &amp;#34;200 &amp;#34;,
      &amp;#34;url &amp;#34;: &amp;#34;http://quickpizza.grafana.com&amp;#34;
    }
  },
  &amp;#34;metric &amp;#34;: &amp;#34;http_req_duration &amp;#34;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JSON&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;#34;type &amp;#34;: &amp;#34;Point &amp;#34;,
  &amp;#34;data &amp;#34;: {
    &amp;#34;time &amp;#34;: &amp;#34;2017-05-09T14:34:45.625742514&amp;#43;02:00 &amp;#34;,
    &amp;#34;value &amp;#34;: 5,
    &amp;#34;tags &amp;#34;: null
  },
  &amp;#34;metric &amp;#34;: &amp;#34;vus &amp;#34;
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To see how tags affect your test-result output, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/real-time/json/&#34;&gt;k6 results output syntax&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;groups&#34;&gt;Groups&lt;/h2&gt;
&lt;p&gt;For extra organization, use &lt;em&gt;groups&lt;/em&gt; to organize a load script by functions.
You can also nest groups for BDD-style testing.&lt;/p&gt;
&lt;p&gt;All metrics emitted in a 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6/group/&#34;&gt;group&lt;/a&gt; have the tag &lt;code&gt;group&lt;/code&gt; with a value of all wrapping group names separated by &lt;code&gt;::&lt;/code&gt; (two colons).
The root group uses the name &amp;rsquo;&amp;rsquo; (empty string).
If you have a single group named &lt;code&gt;cool requests&lt;/code&gt;, the actual value of the &lt;code&gt;group&lt;/code&gt; is &lt;code&gt;::cool requests&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, you could use groups to organize multiple requests by page loads or user actions.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { group } from &amp;#39;k6&amp;#39;;

export default function () {
  group(&amp;#39;visit product listing page&amp;#39;, function () {
    // ...
  });
  group(&amp;#39;add several products to the shopping cart&amp;#39;, function () {
    // ...
  });
  group(&amp;#39;visit login page&amp;#39;, function () {
    // ...
  });
  group(&amp;#39;authenticate&amp;#39;, function () {
    // ...
  });
  group(&amp;#39;checkout process&amp;#39;, function () {
    // ...
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Groups do the following tasks internally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For each &lt;code&gt;group()&lt;/code&gt; function, k6 emits a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/&#34;&gt;group_duration metric&lt;/a&gt;, which contains the total time to execute the group function.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When a taggable resource—a check, request, or custom metric—runs within a group, k6 sets the tag &lt;code&gt;group&lt;/code&gt; with the current group name.
For more info, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#tags&#34;&gt;Tags section&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both options, the &lt;code&gt;group_duration&lt;/code&gt; metric and &lt;code&gt;group tagging&lt;/code&gt;, could help you analyze and visualize complex test results. Check out how they work in your 
    &lt;a href=&#34;/docs/k6/v2.3.x/reference/integrations/#result-store-and-visualization&#34;&gt;k6 result output&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;discouraged-one-group-per-request&#34;&gt;Discouraged: one group per request&lt;/h3&gt;
&lt;p&gt;Wrapping each request within a group might add unnecessary boilerplate.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { group, check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

const id = 5;

export default function () {
  // reconsider this type of code
  group(&amp;#39;get post&amp;#39;, function () {
    http.get(`http://example.com/posts/${id}`);
  });
  group(&amp;#39;list posts&amp;#39;, function () {
    const res = http.get(`http://example.com/posts`);
    check(res, {
      &amp;#39;is status 200&amp;#39;: (r) =&amp;gt; r.status === 200,
    });
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If your code looks like the preceding snippet, consider the following strategies to write cleaner code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For dynamic URLs, use the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/http-requests/#url-grouping&#34;&gt;URL grouping feature&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To provide a meaningful name to your request, set the value of 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/http-requests/#http-request-tags&#34;&gt;tags.name&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To reuse common logic or organize your code better, group logic in functions, or create a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/modules/#local-filesystem-modules&#34;&gt;local JavaScript module&lt;/a&gt; and import it into the test script.&lt;/li&gt;
&lt;li&gt;To model advanced user patterns, check out 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/&#34;&gt;Scenarios&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="tags-and-groups">Tags and Groups&lt;/h1>
&lt;p>A load test usually targets a service with different subsystems and resources.
This can make it hard to pinpoint the issues that are degrading performance.&lt;/p></description></item><item><title>Cookies</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/cookies/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/cookies/</guid><content><![CDATA[&lt;h1 id=&#34;cookies&#34;&gt;Cookies&lt;/h1&gt;
&lt;p&gt;HTTP Cookies are used by websites and apps to store pieces of stateful information on user devices.
Through the &lt;code&gt;Set-Cookie&lt;/code&gt; HTTP header, a server tells a client what information it wants stored on the user machine.&lt;/p&gt;
&lt;p&gt;The user&amp;rsquo;s browser stores the cookie data and associates it with the hostname of the server.
For each subsequent request to that hostname, it includes the stored cookie data in a
&lt;code&gt;Cookie&lt;/code&gt; header.&lt;/p&gt;
&lt;p&gt;You can then control more specific rules for whether to send the cookie data or not,
including limiting it to specific subdomains or paths.
You can also set an expiry date on the cookie and tell the browser to send it only over encrypted (SSL/TLS) connections.&lt;/p&gt;
&lt;h2 id=&#34;cookies-with-k6&#34;&gt;Cookies with k6&lt;/h2&gt;
&lt;p&gt;For most purposes, k6 transparently manages the reception, storage, and transmission of cookies as described.
Testing of your cookie-based web site or app will &lt;em&gt;just work&lt;/em&gt; without requiring any special action of you.&lt;/p&gt;
&lt;p&gt;In some cases, though, you might want more control over cookies.
k6 provides multiple options to do this.
You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/params/&#34;&gt;Directly manipulate HTTP headers&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;Use the more ergonomic cookie API.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following section shows how to use the Cookie API.&lt;/p&gt;
&lt;h2 id=&#34;setting-simple-cookies&#34;&gt;Setting simple cookies&lt;/h2&gt;
&lt;p&gt;To simulate that a cookie has previously been set by a browser and is now supposed to be included
in subsequent requests to the server, include the cookie in the &lt;code&gt;cookies&lt;/code&gt; request parameter:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  http.get(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, {
    cookies: {
      my_cookie: &amp;#39;hello world&amp;#39;,
    },
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This applies only to the cookie for the request in question.
It isn&amp;rsquo;t sent for any subsequent requests.
To send the cookie for subsequent requests, add it to a cookie jar.
By default, k6 has a cookie jar for each VU, which you can interact with to set and inspect cookies:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const jar = http.cookieJar();
  jar.set(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, &amp;#39;my_cookie&amp;#39;, &amp;#39;hello world&amp;#39;);
  http.get(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The per-VU cookie jar stores all cookies received from the server in a &lt;code&gt;Set-Cookie&lt;/code&gt; header.
You can also create &amp;ldquo;local cookie jars&amp;rdquo; that override the per-VU cookie jar (shown in a subsequent section).&lt;/p&gt;
&lt;p&gt;You can also override a cookie that is already part of the per-VU cookie jar:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

export default function () {
  const jar = http.cookieJar();
  jar.set(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, &amp;#39;my_cookie&amp;#39;, &amp;#39;hello world&amp;#39;);

  const cookies = {
    my_cookie: {
      value: &amp;#39;hello world 2&amp;#39;,
      replace: true,
    },
  };

  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, {
    cookies,
  });

  check(res.json(), {
    &amp;#39;cookie has correct value&amp;#39;: (b) =&amp;gt; b.cookies.my_cookie == &amp;#39;hello world 2&amp;#39;,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;accessing-cookies&#34;&gt;Accessing cookies&lt;/h2&gt;
&lt;p&gt;To see which cookies were set for a particular response, look in the &lt;code&gt;cookies&lt;/code&gt; property of the response object:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

export default function () {
  const res = http.post(&amp;#39;https://quickpizza.grafana.com/api/cookies?my_cookie=hello%20world&amp;#39;, {
    redirects: 0,
  });
  check(res, {
    &amp;#34;has cookie &amp;#39;my_cookie&amp;#39;&amp;#34;: (r) =&amp;gt; r.cookies.my_cookie.length &amp;gt; 0,
    &amp;#39;cookie has correct value&amp;#39;: (r) =&amp;gt; r.cookies.my_cookie[0].value === &amp;#39;hello world&amp;#39;,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The response object&amp;rsquo;s &lt;code&gt;cookies&lt;/code&gt; property is a map where the key is the cookie name and the value
is an array of response cookie objects.
This array can support multiple cookies that have the same name but different &lt;code&gt;domain&lt;/code&gt; or &lt;code&gt;path&lt;/code&gt; attributes, as specified in &lt;a href=&#34;https://tools.ietf.org/html/rfc6265#section-5.3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RFC6265&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;properties-of-a-response-cookie-object&#34;&gt;Properties of a response cookie object&lt;/h2&gt;
&lt;p&gt;A response cookie object contains the following properties:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Property&lt;/th&gt;
              &lt;th&gt;Type&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;name&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the name of the cookie&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;value&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;the value of the cookie&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;domain&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;domain deciding what hostnames this cookie should be sent to&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;path&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;limiting the cookie to only be sent if the path of the request matches this value&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;expires&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;when the cookie expires, this needs to be in the RFC1123 format looking like: &lt;code&gt;Mon, 02 Jan 2006 15:04:05 MST&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;max_age&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;number&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;used for the same purpose as expires but defined as the number of seconds a cookie will be valid&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;secure&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;if true, the cookie will only be sent over an encrypted (SSL/TLS) connection&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;http_only&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;if true, the cookie would not be exposed to JavaScript in a browser environment&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;inspecting-a-cookie-in-the-jar&#34;&gt;Inspecting a cookie in the jar&lt;/h2&gt;
&lt;p&gt;To see which cookies are set and stored in the cookie jar for a particular URL,
use the &lt;code&gt;cookieForURL()&lt;/code&gt; method of the cookie jar object:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

export default function () {
  const res = http.post(&amp;#39;https://quickpizza.grafana.com/api/cookies?my_cookie=hello%20world&amp;#39;, {
    redirects: 0,
  });
  const jar = http.cookieJar();
  const cookies = jar.cookiesForURL(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;);
  check(res, {
    &amp;#34;has cookie &amp;#39;my_cookie&amp;#39;&amp;#34;: (r) =&amp;gt; cookies.my_cookie.length &amp;gt; 0,
    &amp;#39;cookie has correct value&amp;#39;: (r) =&amp;gt; cookies.my_cookie[0] === &amp;#39;hello world&amp;#39;,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;cookies&lt;/code&gt; object returned by the jar&amp;rsquo;s &lt;code&gt;cookiesForURL()&lt;/code&gt; method is a map where the key is the
cookie name and the value is an array of cookie values (strings). It is an array to support
multiple cookies having the same name (but different &lt;code&gt;domain&lt;/code&gt; and/or &lt;code&gt;path&lt;/code&gt; attributes), which
is part of &lt;a href=&#34;https://tools.ietf.org/html/rfc6265#section-5.3&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;RFC6265&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;setting-advanced-cookies-with-attributes&#34;&gt;Setting advanced cookies with attributes&lt;/h2&gt;
&lt;p&gt;To set cookies that more tightly controls the behavior of the cookie we must add the cookie to a
cookie jar. An example:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

export default function () {
  const jar = http.cookieJar();
  jar.set(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, &amp;#39;my_cookie&amp;#39;, &amp;#39;hello world&amp;#39;, {
    domain: &amp;#39;quickpizza.grafana.com&amp;#39;,
    path: &amp;#39;/api/cookies&amp;#39;,
    secure: true,
    max_age: 600,
  });
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;);

  check(res, {
    &amp;#39;has status 200&amp;#39;: (r) =&amp;gt; r.status === 200,
    &amp;#39;cookie has correct value&amp;#39;: (r) =&amp;gt; r.json().cookies.my_cookie == &amp;#39;hello world&amp;#39;,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;local-cookie-jars&#34;&gt;Local cookie jars&lt;/h2&gt;
&lt;p&gt;Besides the per-VU cookie jar, you can also create local cookie jars to override the per-VU
cookie jar on a per-request basis:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { check } from &amp;#39;k6&amp;#39;;

export default function () {
  const jar = new http.CookieJar();

  // Add cookie to local jar
  const cookieOptions = {
    domain: &amp;#39;quickpizza.grafana.com&amp;#39;,
    path: &amp;#39;/api/cookies&amp;#39;,
    secure: true,
    max_age: 600,
  };
  jar.set(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, &amp;#39;my_cookie&amp;#39;, &amp;#39;hello world&amp;#39;, cookieOptions);

  // Override per-VU jar with local jar for the following request
  const res = http.get(&amp;#39;https://quickpizza.grafana.com/api/cookies&amp;#39;, { jar });
  check(res, {
    &amp;#39;has status 200&amp;#39;: (r) =&amp;gt; r.status === 200,
    &amp;#39;cookie has correct value&amp;#39;: (r) =&amp;gt; r.json().cookies.my_cookie == &amp;#39;hello world&amp;#39;,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// Example showing two methods how to log all cookies (with attributes) from a HTTP response.
import http from &amp;#39;k6/http&amp;#39;;

function logCookie(c) {
  // Here we log the name and value of the cookie along with additional attributes.
  // For full list of attributes see:
  // https://grafana.com/docs/k6/using-k6/cookies#properties-of-a-response-cookie-object
  const output = `
     ${c.name}: ${c.value}
     tdomain: ${c.domain}
     tpath: ${c.path}
     texpires: ${c.expires}
     thttpOnly: ${c.http_only}
  `;
  console.log(output);
}
export default function () {
  const res = http.get(&amp;#39;https://www.google.com/&amp;#39;);

  // Method 1: Use for-loop and check for non-inherited properties
  for (const name in res.cookies) {
    if (res.cookies.hasOwnProperty(name) !== undefined) {
      logCookie(res.cookies[name][0]);
    }
  }

  // Method 2: Use ES6 Map to loop over Object entries
  new Map(Object.entries(res.cookies)).forEach((v, k) =&amp;gt; {
    logCookie(v[0]);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="cookies">Cookies&lt;/h1>
&lt;p>HTTP Cookies are used by websites and apps to store pieces of stateful information on user devices.
Through the &lt;code>Set-Cookie&lt;/code> HTTP header, a server tells a client what information it wants stored on the user machine.&lt;/p></description></item><item><title>Protocols</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/protocols/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/protocols/</guid><content><![CDATA[&lt;h1 id=&#34;protocols&#34;&gt;Protocols&lt;/h1&gt;
&lt;p&gt;Out of the box, k6 supports the following protocols:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/1.1&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/http-2/&#34;&gt;HTTP/2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/websockets/&#34;&gt;WebSockets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/grpc/&#34;&gt;gRPC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use k6 on more protocols with xk6.&lt;/p&gt;
&lt;h2 id=&#34;upgrade-to-http2-is-automatic&#34;&gt;Upgrade to HTTP/2 is automatic&lt;/h2&gt;
&lt;p&gt;By default, k6 uses HTTP/1.1 when it contacts a server.
If the server reports to k6 that it supports 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/http-2/&#34;&gt;HTTP/2&lt;/a&gt;, k6 upgrades the connection to HTTP/2 instead.&lt;/p&gt;
&lt;p&gt;This is all automatic:
you don&amp;rsquo;t need to do anything special for either the initial use of HTTP/1.1 or the potential protocol upgrade.
However, you might want to verify which protocol is actually being
used for a transaction.
This verification requires an extra step.&lt;/p&gt;
&lt;p&gt;Using 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/protocols/websockets/&#34;&gt;WebSockets&lt;/a&gt; is a bit different, for both the test structure and the VU lifecycle.&lt;/p&gt;
&lt;h2 id=&#34;extend-protocol-support-with-xk6&#34;&gt;Extend protocol support with xk6&lt;/h2&gt;
&lt;p&gt;xk6 is a separate CLI tool that lets you build custom k6 binaries.
Community contributors have already added support for additional protocols,
with extensions for SQL, Kafka, ZeroMQ, Redis, and more.
Refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/explore/&#34;&gt;full list of extensions&lt;/a&gt; and find the ones you want to build. Then follow the 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/build-k6-binary-using-go/&#34;&gt;xk6 guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can build your own extension, too.
See the 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/create/&#34;&gt;tutorials&lt;/a&gt; to get started.&lt;/p&gt;
]]></content><description>&lt;h1 id="protocols">Protocols&lt;/h1>
&lt;p>Out of the box, k6 supports the following protocols:&lt;/p>
&lt;ul>
&lt;li>HTTP/1.1&lt;/li>
&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/protocols/http-2/">HTTP/2&lt;/a>&lt;/li>
&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/protocols/websockets/">WebSockets&lt;/a>&lt;/li>
&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/protocols/grpc/">gRPC&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>You can use k6 on more protocols with xk6.&lt;/p>
&lt;h2 id="upgrade-to-http2-is-automatic">Upgrade to HTTP/2 is automatic&lt;/h2>
&lt;p>By default, k6 uses HTTP/1.1 when it contacts a server.
If the server reports to k6 that it supports
&lt;a href="/docs/k6/v2.3.x/using-k6/protocols/http-2/">HTTP/2&lt;/a>, k6 upgrades the connection to HTTP/2 instead.&lt;/p></description></item><item><title>Environment variables</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/environment-variables/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/environment-variables/</guid><content><![CDATA[&lt;h1 id=&#34;environment-variables&#34;&gt;Environment variables&lt;/h1&gt;
&lt;p&gt;Often, scripts need only minor tweaks to be reusable in different contexts.
Rather than creating several separate scripts for these different contexts or environments, you can use 
    &lt;a href=&#34;/docs/k6/v2.3.x/reference/glossary/#environment-variables&#34;&gt;environment variables&lt;/a&gt; to make parts of your script tweakable.&lt;/p&gt;
&lt;p&gt;You can use environment variables for two main purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Passing environment variables to the k6 Script&lt;/li&gt;
&lt;li&gt;Configuring 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/&#34;&gt;k6 Options&lt;/a&gt; with environment variables&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;passing-environment-variables-to-the-k6-script&#34;&gt;Passing environment variables to the k6 script&lt;/h2&gt;
&lt;p&gt;In k6, the environment variables are exposed through a global &lt;code&gt;__ENV&lt;/code&gt; variable, a JS object.
For reference, see the script example below:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export default function () {
  const res = http.get(`http://${__ENV.MY_HOSTNAME}/`);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By default, &lt;code&gt;__ENV&lt;/code&gt; is a plain, mutable object: assignments like &lt;code&gt;__ENV.MY_HOSTNAME = &#39;other&#39;&lt;/code&gt; persist for the rest of the iteration. To make &lt;code&gt;__ENV&lt;/code&gt; read-only instead, enable the &lt;code&gt;freeze-env&lt;/code&gt; 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/feature-flags/&#34;&gt;feature flag&lt;/a&gt;.
Modifying it will then throw a &lt;code&gt;TypeError&lt;/code&gt; in strict-mode code, or fail silently otherwise.&lt;/p&gt;
&lt;p&gt;The recommended option to pass environment variables to your testing script is to use one or more 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#supply-environment-variables&#34;&gt;&lt;code&gt;-e&lt;/code&gt; / &lt;code&gt;--env&lt;/code&gt; CLI flags&lt;/a&gt;
(this command works the same for all platforms):&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run -e MY_HOSTNAME=test.k6.io script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;h4 id=&#34;-the--e-flag-does-not-configure-options&#34;&gt;⚠ The &lt;code&gt;-e&lt;/code&gt; flag does not configure options&lt;/h4&gt;
&lt;p&gt;This flag just provides variables to the script, which the script can use or ignore.
For example, &lt;code&gt;-e K6_ITERATIONS=120&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; configure the script iterations.&lt;/p&gt;
&lt;p&gt;Compare this behavior with &lt;code&gt;K6_ITERATIONS=120 k6 run script.js&lt;/code&gt;, which &lt;em&gt;does&lt;/em&gt; set iterations.&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&#34;collapse&#34; x-data=&#34;app_collapse()&#34;&gt;
  &lt;button class=&#34;collapse-trigger&#34; @click=&#34;toggle()&#34;&gt;
    &lt;span class=&#34;body-large&#34;&gt;Using System Environment Variables&lt;/span&gt;
    &lt;span class=&#34;collapse-trigger__icon&#34; :class=&#34;{ &#39;collapse-trigger__icon-open&#39; : open }&#34;&gt;
      
  &lt;svg width=&#34;27&#34; height=&#34;26&#34; viewBox=&#34;0 0 27 26&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
&lt;path opacity=&#34;0.2&#34; d=&#34;M1.73047 12.8359C1.73047 19.4634 7.10305 24.8359 13.7305 24.8359C20.3579 24.8359 25.7305 19.4634 25.7305 12.8359C25.7305 6.20852 20.3579 0.835937 13.7305 0.835937C7.10305 0.835937 1.73047 6.20852 1.73047 12.8359Z&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M18.2344 12.8359L9.23438 12.8359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M13.7344 8.33594L13.7344 17.3359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;


    &lt;/span&gt;
  &lt;/button&gt;
  &lt;div class=&#34;collapse-content&#34; x-ref=&#34;content&#34; hidden=&#34;until-found&#34;&gt;
    &lt;div class=&#34;collapse-content__inner&#34; x-ref=&#34;content-inner&#34;&gt;&lt;p&gt;A second option to pass environment variables is to source them from the local system.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;MY_HOSTNAME=test.k6.io k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;windows&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-windows&#34;&gt;set &amp;#34;MY_HOSTNAME=test.k6.io&amp;#34; &amp;amp;&amp;amp; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;powershell&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-powershell&#34;&gt;$env:MY_HOSTNAME=&amp;#34;test.k6.io&amp;#34;; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h4 id=&#34;-warning&#34;&gt;⚠️ Warning&lt;/h4&gt;
&lt;p&gt;By default, passing system environment variables doesn&amp;rsquo;t work for &lt;code&gt;k6 archive&lt;/code&gt;, &lt;code&gt;k6 cloud run&lt;/code&gt;, and &lt;code&gt;k6 inspect&lt;/code&gt;.
This is a security measure to avoid the risk of uploading sensitive data to k6 Cloud.
To override this mode, specify 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#include-system-env-vars&#34;&gt;&amp;ndash;include-system-env-vars&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&#34;configure-k6-options-with-environment-variables&#34;&gt;Configure k6 options with environment variables&lt;/h2&gt;
&lt;p&gt;You can also configure k6 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/&#34;&gt;options&lt;/a&gt; with environment variables.
Consider this script:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;

export default function () {
  const res = http.get(&amp;#39;https://test.k6.io&amp;#39;);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;By default, a local run of this script will execute a single iteration with one virtual user(VU).
To modify the default behavior, pass 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/&#34;&gt;k6 options&lt;/a&gt; as environment variables.
For example, this snippet configures the script to run 10 virtual users for a duration of 10 seconds:&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;Bash&#34;&gt;Bash&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;windows&#34;&gt;windows&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;powershell&#34;&gt;powershell&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;K6_VUS=10 K6_DURATION=10s k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;windows&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-windows&#34;&gt;set &amp;#34;K6_VUS=10 K6_DURATION=10s&amp;#34; &amp;amp;&amp;amp; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;powershell&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-powershell&#34;&gt;$env:K6_VUS=10 ; $env:K6_DURATION=&amp;#34;10s&amp;#34; ; k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As the preceding example shows, you need to prefix &lt;code&gt;K6_&lt;/code&gt; in the environment variable name for k6 to evaluate it as an option parameter.
However, be aware that not all options are supported as environment variables.
You can confirm whether one is by checking the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/&#34;&gt;documentation for each option&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also use the &lt;code&gt;K6_FEATURES&lt;/code&gt; environment variable to enable 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/feature-flags/&#34;&gt;feature flags&lt;/a&gt;, which opt in to new, not-yet-stable k6 behavior.&lt;/p&gt;
&lt;p&gt;Note that when you define options in multiple places, there&amp;rsquo;s an 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/how-to/&#34;&gt;order of precedence&lt;/a&gt; that determines the option to use.
To ensure you&amp;rsquo;re always working with the highest precedence, use command-line flags instead of environment variables:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run -e MY_HOSTNAME=test.k6.io --duration 10s --vus 10 script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/cloud-scripting-extras/cloud-environment-variables/&#34;&gt;Manage environment variables in k6 Cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="environment-variables">Environment variables&lt;/h1>
&lt;p>Often, scripts need only minor tweaks to be reusable in different contexts.
Rather than creating several separate scripts for these different contexts or environments, you can use
&lt;a href="/docs/k6/v2.3.x/reference/glossary/#environment-variables">environment variables&lt;/a> to make parts of your script tweakable.&lt;/p></description></item><item><title>Execution context variables</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/execution-context-variables/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/execution-context-variables/</guid><content><![CDATA[&lt;h1 id=&#34;execution-context-variables&#34;&gt;Execution context variables&lt;/h1&gt;
&lt;p&gt;In some cases, it&amp;rsquo;s really useful to have information about the script&amp;rsquo;s current test-execution state. For example, you might want to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have different VUs run different test logic&lt;/li&gt;
&lt;li&gt;Use different data for each VU and iteration&lt;/li&gt;
&lt;li&gt;Figure out the stage that a test is in&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve these issues, you can use &lt;em&gt;execution context variables&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&#34;k6execution&#34;&gt;k6/execution&lt;/h2&gt;
&lt;p&gt;The 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/&#34;&gt;k6/execution&lt;/a&gt; module exposes details about the current execution state, such as &lt;em&gt;the name of the currently executed scenario&lt;/em&gt;, &lt;em&gt;how many VUs are currently active&lt;/em&gt;, and more.
The module provides test-execution information via three properties:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Property&lt;/th&gt;
              &lt;th&gt;Meta-information and execution details about&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#instance&#34;&gt;instance&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;The current running k6 instance&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#scenario&#34;&gt;scenario&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;The current running scenario&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#vu&#34;&gt;vu&lt;/a&gt;&lt;/td&gt;
              &lt;td&gt;The current VU and iteration&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;example-log-all-context-variables&#34;&gt;Example: log all context variables&lt;/h2&gt;
&lt;p&gt;If you want to experiment with what each context variable looks like as a test runs,
you can copy this template literal into one of your test scripts.&lt;/p&gt;
&lt;p&gt;Note that this omits the &lt;code&gt;abort&lt;/code&gt; variable, since that function would abort the test.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import exec from &amp;#39;k6/execution&amp;#39;;

export default function () {
  console.log(`Execution context

Instance info
-------------
Vus active: ${exec.instance.vusActive}
Iterations completed: ${exec.instance.iterationsCompleted}
Iterations interrupted:  ${exec.instance.iterationsInterrupted}
Iterations completed:  ${exec.instance.iterationsCompleted}
Iterations active:  ${exec.instance.vusActive}
Initialized vus:  ${exec.instance.vusInitialized}
Time passed from start of run(ms):  ${exec.instance.currentTestRunDuration}

Scenario info
-------------
Name of the running scenario: ${exec.scenario.name}
Executor type: ${exec.scenario.executor}
Scenario start timestamp: ${exec.scenario.startTime}
Percentage complete: ${exec.scenario.progress}
Iteration in instance: ${exec.scenario.iterationInInstance}
Iteration in test: ${exec.scenario.iterationInTest}

Test info
---------
All test options: ${exec.test.options}

VU info
-------
Iteration id: ${exec.vu.iterationInInstance}
Iteration in scenario: ${exec.vu.iterationInScenario}
VU ID in instance: ${exec.vu.idInInstance}
VU ID in test: ${exec.vu.idInTest}
VU tags: ${exec.vu.tags}`);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For detailed reference, refer to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/&#34;&gt;k6/execution module&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;additional-examples&#34;&gt;Additional examples&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/examples/data-parameterization/#retrieving-unique-data&#34;&gt;Getting unique data once&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#timing-operations&#34;&gt;Timing operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-execution/#script-naming&#34;&gt;Executing different code blocks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;collapse&#34; x-data=&#34;app_collapse()&#34;&gt;
  &lt;button class=&#34;collapse-trigger&#34; @click=&#34;toggle()&#34;&gt;
    &lt;span class=&#34;body-large&#34;&gt;_VU and _ITER (discouraged)&lt;/span&gt;
    &lt;span class=&#34;collapse-trigger__icon&#34; :class=&#34;{ &#39;collapse-trigger__icon-open&#39; : open }&#34;&gt;
      
  &lt;svg width=&#34;27&#34; height=&#34;26&#34; viewBox=&#34;0 0 27 26&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
&lt;path opacity=&#34;0.2&#34; d=&#34;M1.73047 12.8359C1.73047 19.4634 7.10305 24.8359 13.7305 24.8359C20.3579 24.8359 25.7305 19.4634 25.7305 12.8359C25.7305 6.20852 20.3579 0.835937 13.7305 0.835937C7.10305 0.835937 1.73047 6.20852 1.73047 12.8359Z&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M18.2344 12.8359L9.23438 12.8359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M13.7344 8.33594L13.7344 17.3359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;


    &lt;/span&gt;
  &lt;/button&gt;
  &lt;div class=&#34;collapse-content&#34; x-ref=&#34;content&#34; hidden=&#34;until-found&#34;&gt;
    &lt;div class=&#34;collapse-content__inner&#34; x-ref=&#34;content-inner&#34;&gt;&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;k6 v0.34.0 introduced the &lt;strong&gt;k6/execution&lt;/strong&gt; module. If you are using a version of k6 that doesn&amp;rsquo;t have this module, use &lt;code&gt;__VU&lt;/code&gt; and &lt;code&gt;__ITER&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;__VU&lt;/code&gt; and &lt;code&gt;__ITER&lt;/code&gt; are both global variables with execution-context information that k6 makes available to the test script.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__ITER&lt;/code&gt;: A numeric counter with the current iteration number for a specific VU. Zero-based.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__VU&lt;/code&gt;: Current VU number in use. k6 assigns the value incrementally for each new VU instance, starting from one. The variable is 0 when executing the setup and teardown functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;running-in-k6-cloud&#34;&gt;Running in k6 Cloud&lt;/h3&gt;
&lt;p&gt;When you run tests in &lt;a href=&#34;/docs/grafana-cloud/testing/k6/&#34;&gt;Grafana Cloud k6&lt;/a&gt;, the &lt;strong&gt;__VU&lt;/strong&gt; value is per server/load generator.&lt;/p&gt;
&lt;h3 id=&#34;examples&#34;&gt;Examples&lt;/h3&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;
export default function () {
  http.get(&amp;#39;http://test.k6.io&amp;#39;);
  console.log(`VU: ${__VU}  -  ITER: ${__ITER}`);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can use execution-context variables to configure different test behaviors and parameterizations.
A typical use case is a load test that simulates different users performing a login flow.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { sleep } from &amp;#39;k6&amp;#39;;
export default function () {
  const email = `user&amp;#43;${__VU}@mail.com`;
  const payload = JSON.stringify({ email: email, password: &amp;#39;test&amp;#39; });
  const params = { headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39; } };
  http.post(&amp;#39;http://test.k6.io/login&amp;#39;, payload, params);
  console.log(email);
  // .. continue the user flow
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&#34;grafana-cloud-k6-context-variables&#34;&gt;Grafana Cloud k6 context variables&lt;/h2&gt;
&lt;p&gt;Grafana Cloud k6 injects additional context variables into a running cloud test. These variables provide information about the server (&lt;code&gt;K6_CLOUDRUN_INSTANCE_ID&lt;/code&gt;), load zone (&lt;code&gt;K6_CLOUDRUN_LOAD_ZONE&lt;/code&gt;),instance ID (&lt;code&gt;K6_CLOUDRUN_INSTANCE_ID&lt;/code&gt;), and cloud distribution (&lt;code&gt;K6_CLOUDRUN_DISTRIBUTION&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Refer to &lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/cloud-scripting-extras/cloud-execution-context-variables/&#34;&gt;Cloud execution context variables&lt;/a&gt; for more details.&lt;/p&gt;
]]></content><description>&lt;h1 id="execution-context-variables">Execution context variables&lt;/h1>
&lt;p>In some cases, it&amp;rsquo;s really useful to have information about the script&amp;rsquo;s current test-execution state. For example, you might want to&lt;/p>
&lt;ul>
&lt;li>Have different VUs run different test logic&lt;/li>
&lt;li>Use different data for each VU and iteration&lt;/li>
&lt;li>Figure out the stage that a test is in&lt;/li>
&lt;/ul>
&lt;p>To solve these issues, you can use &lt;em>execution context variables&lt;/em>.&lt;/p></description></item><item><title>Scenarios</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/scenarios/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/scenarios/</guid><content><![CDATA[&lt;h1 id=&#34;scenarios&#34;&gt;Scenarios&lt;/h1&gt;
&lt;p&gt;Scenarios configure how VUs and iteration schedules in granular detail.
With scenarios, you can model diverse &lt;em&gt;workloads&lt;/em&gt;, or traffic patterns in load tests.&lt;/p&gt;
&lt;p&gt;Benefits of using scenarios include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Easier, more flexible test organization.&lt;/strong&gt; You can declare multiple scenarios in the same script,
and each one can independently execute a different JavaScript function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simulate more realistic traffic.&lt;/strong&gt;
Every scenario can use a distinct VU and iteration scheduling pattern,
powered by a purpose-built &lt;a href=&#34;#scenario-executors&#34;&gt;executor&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parallel or sequential workloads.&lt;/strong&gt; Scenarios are independent from each other and run in parallel, though they can be made to appear sequential by setting the &lt;code&gt;startTime&lt;/code&gt; property of each carefully.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Granular results analysis.&lt;/strong&gt; Different environment variables and metric tags can be set per scenario.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;configure-scenarios&#34;&gt;Configure scenarios&lt;/h2&gt;
&lt;p&gt;To configure scenarios, use the &lt;code&gt;scenarios&lt;/code&gt; key in the &lt;code&gt;options&lt;/code&gt; object.
You can give the scenario any name, as long as each scenario name in the script is unique.&lt;/p&gt;
&lt;p&gt;The scenario name appears in the result summary, tags, and so on.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  scenarios: {
    example_scenario: {
      // name of the executor to use
      executor: &amp;#39;shared-iterations&amp;#39;,

      // common scenario configuration
      startTime: &amp;#39;10s&amp;#39;,
      gracefulStop: &amp;#39;5s&amp;#39;,
      env: { EXAMPLEVAR: &amp;#39;testing&amp;#39; },
      tags: { example_tag: &amp;#39;testing&amp;#39; },

      // executor-specific configuration
      vus: 10,
      iterations: 200,
      maxDuration: &amp;#39;10s&amp;#39;,
    },
    another_scenario: {
      /*...*/
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;scenario-executors&#34;&gt;Scenario executors&lt;/h2&gt;
&lt;p&gt;For each k6 scenario, the VU workload is scheduled by an &lt;em&gt;executor&lt;/em&gt;.
Executors configure how long the test runs, whether traffic stays constant or changes, and whether the workload is modeled by VUs or by arrival rate (that is, 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/concepts/open-vs-closed/&#34;&gt;open or closed models&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Your scenario object must define the &lt;code&gt;executor&lt;/code&gt; property with one of the predefined executor names.
Your choice of executor determines how k6 models load.
Choices include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;By number of iterations.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/shared-iterations/&#34;&gt;&lt;code&gt;shared-iterations&lt;/code&gt;&lt;/a&gt; shares iterations between VUs.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/per-vu-iterations/&#34;&gt;&lt;code&gt;per-vu-iterations&lt;/code&gt;&lt;/a&gt; has each VU run the configured iterations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;By number of VUs.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/constant-vus/&#34;&gt;&lt;code&gt;constant-VUs&lt;/code&gt;&lt;/a&gt; sends VUs at a constant number.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/ramping-vus/&#34;&gt;&lt;code&gt;ramping-vus&lt;/code&gt;&lt;/a&gt; ramps the number of VUs according to your configured stages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;By iteration rate.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/constant-arrival-rate/&#34;&gt;&lt;code&gt;constant-arrival-rate&lt;/code&gt;&lt;/a&gt; starts iterations at a constant rate.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/ramping-arrival-rate/&#34;&gt;&lt;code&gt;ramping-arrival-rate&lt;/code&gt;&lt;/a&gt; ramps the iteration rate according to your configured stages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with the generic scenario options, each executor object has additional options specific to its workload.
For the full list, refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/&#34;&gt;Executors&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;options&#34;&gt;Scenario options&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Option&lt;/th&gt;
              &lt;th&gt;Type&lt;/th&gt;
              &lt;th&gt;Description&lt;/th&gt;
              &lt;th&gt;Default&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;executor&lt;sup&gt;(required)&lt;/sup&gt; ️&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;Unique executor name. See the list of possible values in the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/&#34;&gt;executors&lt;/a&gt; section.&lt;/td&gt;
              &lt;td&gt;-&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;startTime&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;Time offset since the start of the test, at which point this scenario should begin execution.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;&amp;quot;0s&amp;quot;&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;gracefulStop&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;Time to wait for iterations to finish executing before stopping them forcefully. To learn more, read 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/concepts/graceful-stop/&#34;&gt;Graceful stop&lt;/a&gt;.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;&amp;quot;30s&amp;quot;&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;exec&lt;/td&gt;
              &lt;td&gt;string&lt;/td&gt;
              &lt;td&gt;Name of exported JS function to execute.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;&amp;quot;default&amp;quot;&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;env&lt;/td&gt;
              &lt;td&gt;object&lt;/td&gt;
              &lt;td&gt;Environment variables specific to this scenario.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;tags&lt;/td&gt;
              &lt;td&gt;object&lt;/td&gt;
              &lt;td&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/&#34;&gt;Tags&lt;/a&gt; specific to this scenario.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;options&lt;/td&gt;
              &lt;td&gt;object&lt;/td&gt;
              &lt;td&gt;Additional options include 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6-browser/options/&#34;&gt;browser options&lt;/a&gt;.&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;{}&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;scenario-example&#34;&gt;Scenario example&lt;/h2&gt;
&lt;p&gt;This script combines two scenarios, with sequencing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;shared_iter_scenario&lt;/code&gt; starts immediately. Ten VUs try to use 100 iterations as quickly as possible (some VUs may use more iterations than others).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;per_vu_scenario&lt;/code&gt; starts after 10s. In this case, ten VUs each run ten iterations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which scenario takes longer?
You can run to discover.
You can also add a &lt;code&gt;maxDuration&lt;/code&gt; property to one or both scenarios.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export const options = {
  scenarios: {
    shared_iter_scenario: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      vus: 10,
      iterations: 100,
      startTime: &amp;#39;0s&amp;#39;,
    },
    per_vu_scenario: {
      executor: &amp;#39;per-vu-iterations&amp;#39;,
      vus: 10,
      iterations: 10,
      startTime: &amp;#39;10s&amp;#39;,
    },
  },
};

export default function () {
  http.get(&amp;#39;https://test.k6.io/&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you run a script with scenarios, k6 output includes high-level information about each one.
For example, if you run the preceding script, &lt;code&gt;k6 run scenario-example.js&lt;/code&gt;,
then k6 reports the scenarios as follows:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;  execution: local
     script: scenario-example.js
     output: -

  scenarios: (100.00%) 2 scenarios, 20 max VUs, 10m40s max duration (incl. grace
ful stop):
           * shared_iter_scenario: 100 iterations shared among 10 VUs (maxDurati
on: 10m0s, gracefulStop: 30s)
           * per_vu_scenario: 10 iterations for each of 10 VUs (maxDuration: 10m
0s, startTime: 10s, gracefulStop: 30s)&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The full output includes the summary metrics, like any default end-of-test summary:&lt;/p&gt;
&lt;div class=&#34;collapse&#34; x-data=&#34;app_collapse()&#34;&gt;
  &lt;button class=&#34;collapse-trigger&#34; @click=&#34;toggle()&#34;&gt;
    &lt;span class=&#34;body-large&#34;&gt;full scenario-example.js output&lt;/span&gt;
    &lt;span class=&#34;collapse-trigger__icon&#34; :class=&#34;{ &#39;collapse-trigger__icon-open&#39; : open }&#34;&gt;
      
  &lt;svg width=&#34;27&#34; height=&#34;26&#34; viewBox=&#34;0 0 27 26&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
&lt;path opacity=&#34;0.2&#34; d=&#34;M1.73047 12.8359C1.73047 19.4634 7.10305 24.8359 13.7305 24.8359C20.3579 24.8359 25.7305 19.4634 25.7305 12.8359C25.7305 6.20852 20.3579 0.835937 13.7305 0.835937C7.10305 0.835937 1.73047 6.20852 1.73047 12.8359Z&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M18.2344 12.8359L9.23438 12.8359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;path d=&#34;M13.7344 8.33594L13.7344 17.3359&#34; stroke=&#34;black&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;


    &lt;/span&gt;
  &lt;/button&gt;
  &lt;div class=&#34;collapse-content&#34; x-ref=&#34;content&#34; hidden=&#34;until-found&#34;&gt;
    &lt;div class=&#34;collapse-content__inner&#34; x-ref=&#34;content-inner&#34;&gt;
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;         /\      Grafana   /‾‾/
    /\  /  \     |\  __   /  /
   /  \/    \    | |/ /  /   ‾‾\
  /          \   |   (  |  (‾)  |
 / __________ \  |_|\_\  \_____/

  execution: local
     script: scenario-example.js
     output: -

  scenarios: (100.00%) 2 scenarios, 20 max VUs, 10m40s max duration (incl. grace
ful stop):
           * shared_iter_scenario: 100 iterations shared among 10 VUs (maxDurati
on: 10m0s, gracefulStop: 30s)
           * per_vu_scenario: 10 iterations for each of 10 VUs (maxDuration: 10m
0s, startTime: 10s, gracefulStop: 30s)

  █ TOTAL RESULTS

    HTTP
    http_req_blocked........................................................: avg=24.59ms  min=1µs      med=4µs      max=263.64ms p(90)=22.48ms  p(95)=245.04ms
    http_req_connecting.....................................................: avg=11.36ms  min=0s       med=0s       max=120.45ms p(90)=10.76ms  p(95)=115.19ms
    http_req_duration.......................................................: avg=115.25ms min=108.25ms med=115.66ms max=170.62ms p(90)=119.59ms p(95)=121.13ms
      { expected_response:true }............................................: avg=115.25ms min=108.25ms med=115.66ms max=170.62ms p(90)=119.59ms p(95)=121.13ms
    http_req_failed.........................................................: 0.00%  0 out of 200
    http_req_receiving......................................................: avg=214.61µs min=15µs     med=73.5µs   max=4.57ms   p(90)=253.4µs  p(95)=1.08ms
    http_req_sending........................................................: avg=17.79µs  min=3µs      med=12µs     max=669µs    p(90)=22µs     p(95)=25µs
    http_req_tls_handshaking................................................: avg=12.01ms  min=0s       med=0s       max=126.23ms p(90)=11.49ms  p(95)=120.04ms
    http_req_waiting........................................................: avg=115.02ms min=107.7ms  med=115.33ms max=170.59ms p(90)=119.54ms p(95)=121.04ms
    http_reqs...............................................................: 200    17.489795/s

    EXECUTION
    iteration_duration......................................................: avg=140.07ms min=108.3ms  med=116.14ms max=383.32ms p(90)=187.14ms p(95)=363.64ms
    iterations..............................................................: 200    17.489795/s
    vus.....................................................................: 10     min=0        max=10
    vus_max.................................................................: 20     min=20       max=20

    NETWORK
    data_received...........................................................: 2.4 MB 209 kB/s
    data_sent...............................................................: 26 kB  2.3 kB/s


  █ SCENARIO: per_vu_scenario

    HTTP
    http_req_blocked...................................: avg=23.52ms  min=1µs      med=4µs      max=244.87ms p(90)=22.39ms  p(95)=234.84ms
    http_req_connecting................................: avg=11.45ms  min=0s       med=0s       max=120.45ms p(90)=10.84ms  p(95)=115.81ms
    http_req_duration..................................: avg=114.86ms min=108.25ms med=115.74ms max=123.17ms p(90)=120.08ms p(95)=121.13ms
    http_req_failed....................................: 0.00%  0 out of 100
    http_req_receiving.................................: avg=195.59µs min=15µs     med=73.5µs   max=4.57ms   p(90)=247.5µs  p(95)=875.99µs
    http_req_sending...................................: avg=20.8µs   min=3µs      med=12µs     max=669µs    p(90)=22.1µs   p(95)=27.09µs
    http_req_tls_handshaking...........................: avg=12.06ms  min=0s       med=0s       max=126.23ms p(90)=11.49ms  p(95)=120.61ms
    http_req_waiting...................................: avg=114.64ms min=107.78ms med=115.38ms max=123.07ms p(90)=120.04ms p(95)=121.04ms
    http_reqs..........................................: 100    8.744897/s

    EXECUTION
    iteration_duration.................................: avg=138.53ms min=108.3ms  med=116.22ms max=363.71ms p(90)=144.44ms p(95)=353.48ms
    iterations.........................................: 100    8.744897/s

    NETWORK
    data_received......................................: 1.2 MB 104 kB/s
    data_sent..........................................: 13 kB  1.1 kB/s


  █ SCENARIO: shared_iter_scenario

    HTTP
    http_req_blocked...................................: avg=25.66ms  min=1µs      med=4µs      max=263.64ms p(90)=24.98ms  p(95)=256.16ms
    http_req_connecting................................: avg=11.27ms  min=0s       med=0s       max=115.37ms p(90)=10.76ms  p(95)=115.15ms
    http_req_duration..................................: avg=115.65ms min=108.38ms med=115.61ms max=170.62ms p(90)=119.11ms p(95)=120.91ms
    http_req_failed....................................: 0.00%  0 out of 100
    http_req_receiving.................................: avg=233.63µs min=22µs     med=73.5µs   max=4.22ms   p(90)=324.6µs  p(95)=1.11ms
    http_req_sending...................................: avg=14.77µs  min=3µs      med=12µs     max=128µs    p(90)=20µs     p(95)=22µs
    http_req_tls_handshaking...........................: avg=11.96ms  min=0s       med=0s       max=124.34ms p(90)=11.64ms  p(95)=118.98ms
    http_req_waiting...................................: avg=115.4ms  min=107.7ms  med=115.33ms max=170.59ms p(90)=118.94ms p(95)=120.85ms
    http_reqs..........................................: 100    8.744897/s

    EXECUTION
    iteration_duration.................................: avg=141.6ms  min=108.46ms med=116.09ms max=383.32ms p(90)=189.98ms p(95)=375.24ms
    iterations.........................................: 100    8.744897/s

    NETWORK
    data_received......................................: 1.2 MB 104 kB/s
    data_sent..........................................: 13 kB  1.1 kB/s

running (00m12.8s), 00/20 VUs, 200 complete and 0 interrupted iterations
shared_iter_scenario ✓ [ 100% ] 10 VUs  00m02.7s/10m0s  100/100 shared iters
per_vu_scenario      ✓ [ 100% ] 10 VUs  00m02.8s/10m0s  100/100 iters, 10 per V&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&#34;run-selected-scenarios&#34;&gt;Run selected scenarios&lt;/h2&gt;
&lt;p&gt;Use 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#scenario-selection&#34;&gt;&lt;code&gt;--scenario&lt;/code&gt;&lt;/a&gt; to run part of a multi-scenario script without editing it or adding environment-variable logic. For example, run only the workload for the API method you are developing, or run a subset on every commit and the full test less often. Selected scenarios keep their configured load.&lt;/p&gt;
&lt;p&gt;Save this example as &lt;code&gt;scenarios.js&lt;/code&gt;:&lt;/p&gt;
&lt;!-- md-k6:fixedscenarios --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  scenarios: {
    api: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      vus: 1,
      iterations: 2,
      exec: &amp;#39;api&amp;#39;,
    },
    checkout: {
      executor: &amp;#39;shared-iterations&amp;#39;,
      vus: 1,
      iterations: 3,
      exec: &amp;#39;checkout&amp;#39;,
    },
  },
  thresholds: {
    iterations: [&amp;#39;count&amp;gt;0&amp;#39;],
    &amp;#39;iterations{scenario:api}&amp;#39;: [&amp;#39;count&amp;gt;0&amp;#39;],
    &amp;#39;iterations{scenario:checkout}&amp;#39;: [&amp;#39;count&amp;gt;0&amp;#39;],
  },
};

export function api() {
  console.log(&amp;#39;API iteration&amp;#39;);
}

export function checkout() {
  console.log(&amp;#39;Checkout iteration&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Select one name, or separate several names with commas:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;k6 run --scenario checkout scenarios.js
k6 run --scenario api,checkout scenarios.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The first command runs three checkout iterations. The second runs both scenarios with their configured iteration counts. Selection preserves each scenario&amp;rsquo;s executor, load, timing, function, environment, tags, and browser settings. Other global options and the normal test lifecycle still apply, including &lt;code&gt;setup()&lt;/code&gt; and &lt;code&gt;teardown()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Names must exist in the configured &lt;code&gt;scenarios&lt;/code&gt; object after the script&amp;rsquo;s initialization code runs. A &lt;code&gt;default&lt;/code&gt; export alone does not define a selectable scenario; &lt;code&gt;--scenario default&lt;/code&gt; requires an explicitly configured &lt;code&gt;scenarios.default&lt;/code&gt;. An empty selection or an unknown name returns an error.&lt;/p&gt;
&lt;h3 id=&#34;load-options-and-thresholds&#34;&gt;Load options and thresholds&lt;/h3&gt;
&lt;p&gt;You cannot combine &lt;code&gt;--scenario&lt;/code&gt; with &lt;code&gt;--vus&lt;/code&gt;, &lt;code&gt;--duration&lt;/code&gt;, &lt;code&gt;--iterations&lt;/code&gt;, or &lt;code&gt;--stage&lt;/code&gt;. k6 ignores the corresponding top-level settings from the script, a configuration file, or environment variables and logs a warning. Settings inside selected scenarios remain intact. Execution segments remain active and can reduce the work assigned to selected scenarios.&lt;/p&gt;
&lt;p&gt;Selection removes thresholds whose &lt;code&gt;scenario&lt;/code&gt; tag names a configured scenario that you excluded, and logs a warning. In the example, selecting &lt;code&gt;checkout&lt;/code&gt; skips the API threshold and keeps the global and checkout thresholds. Global thresholds, filters without a &lt;code&gt;scenario&lt;/code&gt; tag, and filters naming a selected or unconfigured scenario remain active. A global count threshold that expects the full workload can still fail a partial run.&lt;/p&gt;
&lt;p&gt;A skipped threshold stays skipped even if another scenario emits samples with the excluded scenario&amp;rsquo;s tag. For example, a selected checkout scenario can emit a custom metric tagged &lt;code&gt;scenario:api&lt;/code&gt;; an API threshold removed by selection will not evaluate those samples. Refer to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/#set-thresholds-for-specific-tags&#34;&gt;thresholds for specific tags&lt;/a&gt; when choosing which assertions should remain shared.&lt;/p&gt;
&lt;h3 id=&#34;cloud-runs-and-archives&#34;&gt;Cloud runs and archives&lt;/h3&gt;
&lt;p&gt;The same selection works with &lt;code&gt;k6 cloud run&lt;/code&gt;, including &lt;code&gt;--local-execution&lt;/code&gt;, and &lt;code&gt;k6 archive&lt;/code&gt;. Archives save the selected scenarios and remaining thresholds, so you can replay an archive without repeating &lt;code&gt;--scenario&lt;/code&gt;. Omitting the flag on replay does not restore excluded scenarios or thresholds.&lt;/p&gt;
&lt;h3 id=&#34;run-each-selected-scenario-once&#34;&gt;Run each selected scenario once&lt;/h3&gt;
&lt;p&gt;To check the selected workloads with one iteration each, combine &lt;code&gt;--scenario&lt;/code&gt; with &lt;code&gt;--once&lt;/code&gt;. Selection chooses which scenarios run; &lt;code&gt;--once&lt;/code&gt; gives each one a single VU and iteration:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;sh&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-sh&#34;&gt;k6 run --scenario api,checkout --once scenarios.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This command runs one API iteration and one checkout iteration. Each scenario keeps its function, environment, tags, and browser settings, while &lt;code&gt;--once&lt;/code&gt; resets its executor and timing to &lt;code&gt;shared-iterations&lt;/code&gt;, &lt;code&gt;startTime: &#39;0s&#39;&lt;/code&gt;, &lt;code&gt;maxDuration: &#39;10m&#39;&lt;/code&gt;, and &lt;code&gt;gracefulStop: &#39;30s&#39;&lt;/code&gt;. Execution segments cannot be combined with &lt;code&gt;--once&lt;/code&gt;. Bare &lt;code&gt;--once&lt;/code&gt; still rejects a script with multiple scenarios; explicit selection tells k6 which ones to run.&lt;/p&gt;
]]></content><description>&lt;h1 id="scenarios">Scenarios&lt;/h1>
&lt;p>Scenarios configure how VUs and iteration schedules in granular detail.
With scenarios, you can model diverse &lt;em>workloads&lt;/em>, or traffic patterns in load tests.&lt;/p>
&lt;p>Benefits of using scenarios include:&lt;/p></description></item><item><title>Secret source</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/secret-source/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/secret-source/</guid><content><![CDATA[&lt;h1 id=&#34;secret-source&#34;&gt;Secret source&lt;/h1&gt;
&lt;p&gt;Secret sources provide a secure way for k6 to retrieve and use secrets. Unlike values from environment variables or files, values from secret sources are automatically redacted from k6 logs before propagation through the system.&lt;/p&gt;
&lt;p&gt;Access secrets through the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-secrets/&#34;&gt;&lt;code&gt;k6/secrets&lt;/code&gt;&lt;/a&gt; JavaScript API. All secrets are redacted from logs.&lt;/p&gt;
&lt;h2 id=&#34;configure-secret-sources&#34;&gt;Configure secret sources&lt;/h2&gt;
&lt;p&gt;Configure secret sources using the &lt;code&gt;--secret-source&lt;/code&gt; CLI flag. You can configure multiple secret sources simultaneously.&lt;/p&gt;
&lt;h2 id=&#34;built-in-secret-sources&#34;&gt;Built-in secret sources&lt;/h2&gt;
&lt;p&gt;The following built-in secret sources are available for local testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/secret-source/file/&#34;&gt;&lt;code&gt;file&lt;/code&gt;&lt;/a&gt;: Reads secrets from a &lt;code&gt;key=value&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/secret-source/mock/&#34;&gt;&lt;code&gt;mock&lt;/code&gt;&lt;/a&gt;: Reads secrets from CLI arguments.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/secret-source/url/&#34;&gt;&lt;code&gt;url&lt;/code&gt;&lt;/a&gt;: Fetches secrets from HTTP endpoints.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following built-in secret source is available for &lt;code&gt;k6 cloud run --local-execution&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/secret-source/cloud/&#34;&gt;&lt;code&gt;cloud&lt;/code&gt;&lt;/a&gt;: Fetches secrets from 
    &lt;a href=&#34;/docs/k6/v2.3.x/grafana-cloud-k6/&#34;&gt;Grafana Cloud k6&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;secret-source-extensions&#34;&gt;Secret source extensions&lt;/h2&gt;
&lt;p&gt;You can implement a secret source as an 
    &lt;a href=&#34;/docs/k6/v2.3.x/extensions/&#34;&gt;extension&lt;/a&gt; for k6.&lt;/p&gt;
&lt;h2 id=&#34;example-script&#34;&gt;Example script&lt;/h2&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import secrets from &amp;#39;k6/secrets&amp;#39;;

export default async () =&amp;gt; {
  const my_secret = await secrets.get(&amp;#39;cool&amp;#39;); // Retrieves secret by identifier
  console.log(my_secret);
  const response = await http.asyncRequest(&amp;#39;GET&amp;#39;, &amp;#39;https://httpbin.org/get&amp;#39;, null, {
    headers: {
      &amp;#39;Custom-Authentication&amp;#39;: `Bearer ${await secrets.get(&amp;#39;else&amp;#39;)}`,
    },
  });
  console.log(response.body);
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the script with the following secrets file:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;text&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-text&#34;&gt;cool=some
else=source&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The following output shows how secrets are redacted in logs, shown as &lt;code&gt;***SECRET_REDACTED***&lt;/code&gt;, while remaining accessible to the script.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;$ k6 run --secret-source=file=file.secret secrets.test.js
...
INFO[0000] ***SECRET_REDACTED***                         source=console
INFO[0001] {
  &amp;#34;args&amp;#34;: {},
  &amp;#34;headers&amp;#34;: {
    &amp;#34;Custom-Authentication&amp;#34;: &amp;#34;Bearer ***SECRET_REDACTED***&amp;#34;,
    &amp;#34;Host&amp;#34;: &amp;#34;httpbin.org&amp;#34;,
    &amp;#34;User-Agent&amp;#34;: &amp;#34;k6/0.57.0 (https://k6.io/)&amp;#34;,
    &amp;#34;X-Amzn-Trace-Id&amp;#34;: &amp;#34;Root=1-67dd638b-4243896a2fa1b1b45bc63eaa&amp;#34;
  },
  &amp;#34;origin&amp;#34;: &amp;#34;&amp;lt;my actual IP&amp;gt;&amp;#34;,
  &amp;#34;url&amp;#34;: &amp;#34;https://httpbin.org/get&amp;#34;
}  ***SECRET_REDACTED***=console&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
]]></content><description>&lt;h1 id="secret-source">Secret source&lt;/h1>
&lt;p>Secret sources provide a secure way for k6 to retrieve and use secrets. Unlike values from environment variables or files, values from secret sources are automatically redacted from k6 logs before propagation through the system.&lt;/p></description></item><item><title>Test authoring</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/test-authoring/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/test-authoring/</guid><content><![CDATA[&lt;h1 id=&#34;test-authoring&#34;&gt;Test authoring&lt;/h1&gt;
&lt;!-- TODO: Add content --&gt;
&lt;ul&gt;&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/test-authoring/create-test-script-using-the-cli/&#34;&gt;Create a test script using the CLI&lt;/a&gt;&lt;/li&gt;&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/test-authoring/create-test-script-using-openapi/&#34;&gt;Create a test script from an OpenAPI definition file&lt;/a&gt;&lt;/li&gt;&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/test-authoring/test-builder/&#34;&gt;Test builder&lt;/a&gt;&lt;/li&gt;&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/test-authoring/create-tests-from-recordings/&#34;&gt;Create tests from recordings&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
]]></content><description>&lt;h1 id="test-authoring">Test authoring&lt;/h1>
&lt;!-- TODO: Add content -->
&lt;ul>&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/test-authoring/create-test-script-using-the-cli/">Create a test script using the CLI&lt;/a>&lt;/li>&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/test-authoring/create-test-script-using-openapi/">Create a test script from an OpenAPI definition file&lt;/a>&lt;/li>&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/test-authoring/test-builder/">Test builder&lt;/a>&lt;/li>&lt;li>
&lt;a href="/docs/k6/v2.3.x/using-k6/test-authoring/create-tests-from-recordings/">Create tests from recordings&lt;/a>&lt;/li>&lt;/ul></description></item><item><title>JavaScript and TypeScript compatibility mode</title><link>https://grafana.com/docs/k6/v2.3.x/using-k6/javascript-typescript-compatibility-mode/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/using-k6/javascript-typescript-compatibility-mode/</guid><content><![CDATA[&lt;h1 id=&#34;javascript-compatibility-mode&#34;&gt;JavaScript compatibility mode&lt;/h1&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;If you&amp;rsquo;re using k6 v0.53 or higher, the compatibility mode feature doesn&amp;rsquo;t have much impact on the k6 default behavior. Refer to &lt;a href=&#34;https://github.com/grafana/k6/issues/3864&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;this GitHub issue&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;Starting on k6 v0.57, TypeScript support is enabled by default, and the &lt;code&gt;experimental-enhanced-mode&lt;/code&gt; option has been removed.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;k6 offers two JavaScript compatibility modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#base-mode&#34;&gt;Base mode&lt;/a&gt;: Only uses native support in k6 and the underlying JavaScript runtime. For k6 v0.53.0 or higher, it has the same functionality as &lt;code&gt;extended&lt;/code&gt; apart from the &lt;code&gt;global&lt;/code&gt; aliasing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#extended-mode&#34;&gt;Extended mode&lt;/a&gt;: Similar to base mode, with an additional alias from &lt;code&gt;global&lt;/code&gt; to &lt;code&gt;globalThis&lt;/code&gt; for Node.js compatibility. This is the default mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After k6 v0.53.0, the only difference between the base and extended modes is that &lt;code&gt;global&lt;/code&gt;, the Node.js global variable, is aliased to the value of &lt;code&gt;globalThis&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When running tests, you can change the mode by using the &lt;code&gt;--compatibility-mode&lt;/code&gt; option:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;button-div&#34;&gt;
      &lt;button class=&#34;expand-table-btn&#34;&gt;Expand table&lt;/button&gt;
    &lt;/div&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Env&lt;/th&gt;
              &lt;th&gt;CLI&lt;/th&gt;
              &lt;th&gt;Code / Config file&lt;/th&gt;
              &lt;th&gt;Default&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;code&gt;K6_COMPATIBILITY_MODE&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;--compatibility-mode&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;N/A&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;&amp;quot;extended&amp;quot;&lt;/code&gt;&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;extended-mode&#34;&gt;Extended mode&lt;/h2&gt;
&lt;p&gt;By default, k6 uses the &lt;code&gt;--compatibility-mode=extended&lt;/code&gt; mode:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;base-mode&#34;&gt;Base mode&lt;/h2&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;cli&#34;&gt;cli&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;env&#34;&gt;env&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;cli&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-cli&#34;&gt;k6 run --compatibility-mode=base script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;env&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-env&#34;&gt;K6_COMPATIBILITY_MODE=base k6 run script.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;typescript-support&#34;&gt;Typescript support&lt;/h2&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;cli&#34;&gt;cli&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;env&#34;&gt;env&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;cli&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-cli&#34;&gt;k6 run script.ts&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;env&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-env&#34;&gt;k6 run script.ts&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;k6 uses &lt;a href=&#34;https://esbuild.github.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;esbuild&lt;/a&gt; to transpile TypeScript (TS) code for all files that have the &lt;code&gt;.ts&lt;/code&gt; extension.&lt;/p&gt;
&lt;p&gt;TypeScript support is partial as it strips the type information but doesn&amp;rsquo;t provide type safety.&lt;/p&gt;
&lt;h2 id=&#34;commonjs-example&#34;&gt;CommonJS Example&lt;/h2&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;const http = require(&amp;#39;k6/http&amp;#39;);
const k6 = require(&amp;#39;k6&amp;#39;);

module.exports.options = {
  vus: 10,
  duration: &amp;#39;30s&amp;#39;,
};

module.exports.default = function () {
  http.get(&amp;#39;http://test.k6.io&amp;#39;);
  k6.sleep(1);
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;h3 id=&#34;-about-require&#34;&gt;⚠️ About require()&lt;/h3&gt;
&lt;p&gt;Note that &lt;code&gt;require()&lt;/code&gt; is a custom k6 implementation of module
loading, which doesn&amp;rsquo;t behave in the same way as the
&lt;a href=&#34;https://nodejs.org/api/modules.html#modules_require_id&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;require() call in Node.js&lt;/a&gt;.
Specifically, it only handles loading of built-in k6 modules,
scripts on the local filesystem, and remote scripts over HTTP(S),
but it does &lt;em&gt;not&lt;/em&gt; support the
&lt;a href=&#34;https://nodejs.org/api/modules.html#modules_all_together&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Node.js module resolution algorithm&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;bundling-with-babel-outside-of-k6&#34;&gt;Bundling with Babel outside of k6&lt;/h2&gt;
&lt;p&gt;The examples below demonstrate the use of Babel with bundlers like &lt;a href=&#34;https://webpack.js.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Webpack&lt;/a&gt; and &lt;a href=&#34;https://rollupjs.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Rollup&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-template-es6&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-template-es6&lt;/a&gt;: Template using Webpack and Babel to bundle k6 tests.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/grafana/k6-rollup-example&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-rollup-example&lt;/a&gt;: Example using Rollup and Babel to bundle a testing project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;read-more&#34;&gt;Read more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/running-large-tests/&#34;&gt;Running large tests&lt;/a&gt;: Optimize k6 for better performance.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/modules/&#34;&gt;k6 Modules&lt;/a&gt;: Different options to import modules in k6.&lt;/li&gt;
&lt;li&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/reference/archive/&#34;&gt;k6 Archive Command&lt;/a&gt;: The &lt;code&gt;k6 archive&lt;/code&gt; command bundles all k6 test dependencies into a &lt;code&gt;tar&lt;/code&gt; file, which can then be used for execution. It may also reduce the execution startup time.&lt;/li&gt;
&lt;/ul&gt;
]]></content><description>&lt;h1 id="javascript-compatibility-mode">JavaScript compatibility mode&lt;/h1>
&lt;div class="admonition admonition-note">&lt;blockquote>&lt;p class="title text-uppercase">Note&lt;/p>&lt;p>If you&amp;rsquo;re using k6 v0.53 or higher, the compatibility mode feature doesn&amp;rsquo;t have much impact on the k6 default behavior. Refer to &lt;a href="https://github.com/grafana/k6/issues/3864" target="_blank" rel="noopener noreferrer">this GitHub issue&lt;/a> for more details.&lt;/p></description></item></channel></rss>