<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Establishing a baseline on Grafana Labs</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/</link><description>Recent content in Establishing a baseline on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/index.xml" rel="self" type="application/rss+xml"/><item><title>Establishing a baseline</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/14-establishing-baseline-intro/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/14-establishing-baseline-intro/</guid><content><![CDATA[&lt;h2 id=&#34;establishing-a-baseline&#34;&gt;Establishing a baseline&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What you learned in Module 2:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How k6 runs your test (virtual users, iterations, three script parts)&lt;/li&gt;
&lt;li&gt;How to install k6, write a script, and run it locally&lt;/li&gt;
&lt;li&gt;How to send the same run to Grafana Cloud k6 for stored results and dashboards&lt;/li&gt;
&lt;li&gt;Which built-in metrics k6 reports and when to lean on local vs cloud execution&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;What you&amp;rsquo;ll do in this module:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What is a baseline?&lt;/strong&gt; — Why it comes before stress, spike, and soak&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key baseline metrics&lt;/strong&gt; — Latency, throughput, errors, and check pass rate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Designing a load profile&lt;/strong&gt; — Stages and ramping&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checks vs thresholds&lt;/strong&gt; — Per-response correctness vs whole-run pass or fail&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Results to thresholds&lt;/strong&gt; — Set thresholds from what you measured&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;When thresholds fail&lt;/strong&gt; — Terminal output, exit codes, and regression patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Establish a baseline learning path&lt;/strong&gt; — The hands-on path&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Baseline complete&lt;/strong&gt; — Debrief and what carries into the wrap-up&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Estimated time:&lt;/strong&gt; 20-25 minutes&lt;/p&gt;
]]></content><description>&lt;h2 id="establishing-a-baseline">Establishing a baseline&lt;/h2>
&lt;p>&lt;strong>What you learned in Module 2:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>How k6 runs your test (virtual users, iterations, three script parts)&lt;/li>
&lt;li>How to install k6, write a script, and run it locally&lt;/li>
&lt;li>How to send the same run to Grafana Cloud k6 for stored results and dashboards&lt;/li>
&lt;li>Which built-in metrics k6 reports and when to lean on local vs cloud execution&lt;/li>
&lt;/ul>
&lt;hr />
&lt;p>&lt;strong>What you&amp;rsquo;ll do in this module:&lt;/strong>&lt;/p></description></item><item><title>The baseline methodology</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/15-what-is-a-baseline/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/15-what-is-a-baseline/</guid><content><![CDATA[&lt;h2 id=&#34;scenario&#34;&gt;Scenario&lt;/h2&gt;
&lt;p&gt;A change &lt;strong&gt;passes functional tests&lt;/strong&gt; and feels fine when you click through alone, but the &lt;strong&gt;p95&lt;/strong&gt; you care about was never written down. Under &lt;strong&gt;dozens of concurrent users&lt;/strong&gt;, the same build might already be slow or noisy; you would not know until a release or an incident. A baseline turns &amp;ldquo;it felt OK&amp;rdquo; into &lt;strong&gt;numbers you can compare&lt;/strong&gt; next week.&lt;/p&gt;
&lt;h2 id=&#34;the-baseline-workflow&#34;&gt;The baseline workflow&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Step&lt;/th&gt;
              &lt;th&gt;What you do&lt;/th&gt;
              &lt;th&gt;What it produces&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;1. Observe&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Run without thresholds at realistic load&lt;/td&gt;
              &lt;td&gt;Actual p95, error rate, throughput&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;2. Set&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Add thresholds based on observed values &#43; headroom&lt;/td&gt;
              &lt;td&gt;Script with pass/fail criteria&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;3. Validate&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Re-run with thresholds, confirm consistency&lt;/td&gt;
              &lt;td&gt;Working quality gate&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;what-is-a-baseline.svg&#34;
  alt=&#34;The baseline methodology: observe, set, validate&#34;/&gt;&lt;/p&gt;
&lt;h2 id=&#34;why-this-order-matters&#34;&gt;Why this order matters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observe before you set thresholds.&lt;/strong&gt; Use measured values. Guesses drift and break trust in the gate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validate before you wire CI.&lt;/strong&gt; Stable thresholds first. Flaky gates waste the whole team’s time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leave headroom on p95.&lt;/strong&gt; A gap between what you saw and the limit absorbs normal jitter. It still catches real regressions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-shift&#34;&gt;The shift&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Before baselines&lt;/th&gt;
              &lt;th&gt;After baselines&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&amp;ldquo;The results looked okay to me&amp;rdquo;&lt;/td&gt;
              &lt;td&gt;The test passed with exit code 0&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Someone reviews metrics manually&lt;/td&gt;
              &lt;td&gt;CI/CD decides automatically&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Regressions found in production&lt;/td&gt;
              &lt;td&gt;Regressions blocked at merge&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;]]></content><description>&lt;h2 id="scenario">Scenario&lt;/h2>
&lt;p>A change &lt;strong>passes functional tests&lt;/strong> and feels fine when you click through alone, but the &lt;strong>p95&lt;/strong> you care about was never written down. Under &lt;strong>dozens of concurrent users&lt;/strong>, the same build might already be slow or noisy; you would not know until a release or an incident. A baseline turns &amp;ldquo;it felt OK&amp;rdquo; into &lt;strong>numbers you can compare&lt;/strong> next week.&lt;/p></description></item><item><title>Reading k6 output</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/16-key-baseline-metrics/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/16-key-baseline-metrics/</guid><content><![CDATA[&lt;h2 id=&#34;what-good-looks-like-in-the-summary&#34;&gt;What &amp;ldquo;good&amp;rdquo; looks like in the summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Thresholds section&lt;/strong&gt; shows your gate first; every line should be green before you trust CI with the script.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;p95 on &lt;code&gt;http_req_duration&lt;/code&gt;&lt;/strong&gt; is stable across two runs at the same profile (small drift is normal; wild swings mean the profile or environment is not ready).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;http_req_failed&lt;/code&gt;&lt;/strong&gt; stays at zero or inside your agreed budget; mystery 4xx or 5xx under steady load deserve a check or environment fix before you tighten thresholds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checks&lt;/strong&gt; reflect a real success condition, not only &amp;ldquo;HTTP 200.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;sample-k6-terminal-output&#34;&gt;Sample k6 terminal output&lt;/h2&gt;
&lt;p&gt;The block below matches the &lt;strong&gt;k6 v1 end-of-test summary&lt;/strong&gt; layout (thresholds first, then grouped totals). Layout and labels can change between versions; for section order, &lt;code&gt;--summary-mode&lt;/code&gt;, and other options, refer to &lt;a href=&#34;/docs/k6/latest/results-output/end-of-test/&#34;&gt;End-of-test summary&lt;/a&gt; in the k6 documentation.&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;  █ THRESHOLDS

    http_req_duration
    ✓ &amp;#39;p(95)&amp;lt;1500&amp;#39; p(95)=148.21ms
    ✓ &amp;#39;p(90)&amp;lt;2000&amp;#39; p(90)=146.88ms

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


  █ TOTAL RESULTS

    checks_total.......................: 90      13.122179/s
    checks_succeeded...................: 100.00% 90 out of 90
    checks_failed......................: 0.00%   0 out of 90

    ✓ status is 200
    ✓ body is not empty

    CUSTOM
    custom_waiting_time................: avg=152.355556 min=120      med=141      max=684      p(90)=147.2    p(95)=148.8

    HTTP
    http_req_duration..................: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
      { expected_response:true }.......: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
    http_req_failed....................: 0.00%  0 out of 45
    http_reqs..........................: 45     6.56109/s

    EXECUTION
    iteration_duration.................: avg=152.38ms   min=119.37ms med=141.27ms max=684.62ms p(90)=147.11ms p(95)=148.39ms
    iterations.........................: 45     6.56109/s
    vus................................: 1      min=1       max=1
    vus_max............................: 1      min=1       max=1

    NETWORK
    data_received......................: 519 kB 76 kB/s
    data_sent..........................: 4.9 kB 718 B/s&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;where-to-look&#34;&gt;Where to look&lt;/h2&gt;
&lt;p&gt;Values in the &lt;strong&gt;Example&lt;/strong&gt; column are taken from the sample summary above so the table stays internally consistent.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;What you need&lt;/th&gt;
              &lt;th&gt;Where to find it&lt;/th&gt;
              &lt;th&gt;Example from sample&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Latency (p95)&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;http_req_duration&lt;/code&gt; → &lt;code&gt;p(95)&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;148.21 ms&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;http_reqs&lt;/code&gt; → numeric rate &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;/s&lt;/code&gt; on that line (here &lt;code&gt;6.56109/s&lt;/code&gt;)&lt;/td&gt;
              &lt;td&gt;6.56109/s&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Error rate&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;http_req_failed&lt;/code&gt; → percentage&lt;/td&gt;
              &lt;td&gt;0.00%&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Check pass rate&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;checks_succeeded&lt;/code&gt; / &lt;code&gt;checks_total&lt;/code&gt; (summary layout varies by version)&lt;/td&gt;
              &lt;td&gt;100.00% (90 of 90)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;VU count&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;vus&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;1&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;reading-threshold-results&#34;&gt;Reading threshold results&lt;/h2&gt;
&lt;p&gt;When thresholds are set, each one shows a verdict:&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;  █ THRESHOLDS

    http_req_duration
    ✓ &amp;#39;p(95)&amp;lt;1500&amp;#39; p(95)=148.21ms
    ✓ &amp;#39;p(90)&amp;lt;2000&amp;#39; p(90)=146.88ms

    http_req_failed
    ✓ &amp;#39;rate&amp;lt;0.01&amp;#39; rate=0.00%&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;✓&lt;/strong&gt; (check mark) means the threshold passed. &lt;strong&gt;✗&lt;/strong&gt; (X) means the threshold was breached (exit code 99).&lt;/p&gt;
&lt;h2 id=&#34;what-the-numbers-mean-together&#34;&gt;What the numbers mean together&lt;/h2&gt;
&lt;p&gt;Read one run through &lt;strong&gt;three lenses&lt;/strong&gt;. You almost never trust a single number alone.&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Lens&lt;/th&gt;
              &lt;th&gt;Ask&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Latency (p95)&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Are responses getting slower over time?&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Does request rate keep up with how many VUs you added?&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Correctness&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Are HTTP failures or check failures climbing?&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;&lt;strong&gt;Four common stories&lt;/strong&gt; (heuristics for HTTP tests at steady VUs, not guarantees):&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;If you see…&lt;/th&gt;
              &lt;th&gt;Often means…&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;p95 steady and low&lt;/strong&gt;, throughput matches your ramp, &lt;strong&gt;errors near zero&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;The system looks &lt;strong&gt;healthy at this load&lt;/strong&gt;.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;p95 climbs&lt;/strong&gt; while VUs stay flat and &lt;strong&gt;throughput stalls or falls&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Work is &lt;strong&gt;backing up&lt;/strong&gt; (responses slower, queueing, or saturation).&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Errors or failed checks rise&lt;/strong&gt; while &lt;strong&gt;p95 stays low&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Answers are &lt;strong&gt;wrong or rejected&lt;/strong&gt; even when they arrive fast. Reread checks and response bodies.&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Throughput drops&lt;/strong&gt; with &lt;strong&gt;the same VU count&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Each request is &lt;strong&gt;costing more time&lt;/strong&gt; somewhere (network, app, or dependencies). Pair with &lt;code&gt;http_req_duration&lt;/code&gt; trends.&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;]]></content><description>&lt;h2 id="what-good-looks-like-in-the-summary">What &amp;ldquo;good&amp;rdquo; looks like in the summary&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Thresholds section&lt;/strong> shows your gate first; every line should be green before you trust CI with the script.&lt;/li>
&lt;li>&lt;strong>p95 on &lt;code>http_req_duration&lt;/code>&lt;/strong> is stable across two runs at the same profile (small drift is normal; wild swings mean the profile or environment is not ready).&lt;/li>
&lt;li>&lt;strong>&lt;code>http_req_failed&lt;/code>&lt;/strong> stays at zero or inside your agreed budget; mystery 4xx or 5xx under steady load deserve a check or environment fix before you tighten thresholds.&lt;/li>
&lt;li>&lt;strong>Checks&lt;/strong> reflect a real success condition, not only &amp;ldquo;HTTP 200.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;h2 id="sample-k6-terminal-output">Sample k6 terminal output&lt;/h2>
&lt;p>The block below matches the &lt;strong>k6 v1 end-of-test summary&lt;/strong> layout (thresholds first, then grouped totals). Layout and labels can change between versions; for section order, &lt;code>--summary-mode&lt;/code>, and other options, refer to &lt;a href="/docs/k6/latest/results-output/end-of-test/">End-of-test summary&lt;/a> in the k6 documentation.&lt;/p></description></item><item><title>Designing a realistic load profile</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/17-designing-load-profile/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/17-designing-load-profile/</guid><content><![CDATA[&lt;h2 id=&#34;load-profile-shape&#34;&gt;Load profile shape&lt;/h2&gt;
&lt;p&gt;A baseline load profile has three phases.&lt;/p&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;designing-load-profile.svg&#34;
  alt=&#34;Load profile diagram showing ramp-up, steady state, and ramp-down&#34;/&gt;&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Phase&lt;/th&gt;
              &lt;th&gt;Purpose&lt;/th&gt;
              &lt;th&gt;Duration&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Ramp-up&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Gradually increase VUs to avoid cold-start spikes&lt;/td&gt;
              &lt;td&gt;30 seconds to 1 minute&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Steady state&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Hold at target load to collect stable metrics&lt;/td&gt;
              &lt;td&gt;1-2 minutes minimum&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Ramp-down&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Reduce VUs back to zero for clean shutdown&lt;/td&gt;
              &lt;td&gt;30 seconds&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;scenarios-executors-and-stages&#34;&gt;Scenarios, executors, and stages&lt;/h2&gt;
&lt;p&gt;k6 uses &lt;a href=&#34;/docs/k6/latest/using-k6/scenarios/&#34;&gt;&lt;strong&gt;scenarios&lt;/strong&gt;&lt;/a&gt; to describe how a test runs. Each scenario picks an &lt;a href=&#34;/docs/k6/latest/using-k6/scenarios/executors/&#34;&gt;&lt;strong&gt;executor&lt;/strong&gt;&lt;/a&gt; that schedules virtual users or iteration rate. The &lt;a href=&#34;/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/&#34;&gt;&lt;strong&gt;ramping-vus&lt;/strong&gt;&lt;/a&gt; executor changes the target number of VUs over time using a &lt;code&gt;stages&lt;/code&gt; array, which matches the ramp-up, steady-state, and ramp-down idea above.&lt;/p&gt;
&lt;p&gt;Putting &lt;code&gt;stages&lt;/code&gt; on the root &lt;code&gt;options&lt;/code&gt; object is a shortcut for a single scenario that uses the ramping-vus executor. For several traffic shapes in one script, or when you want scenario names in results, configure the &lt;code&gt;scenarios&lt;/code&gt; object explicitly instead.&lt;/p&gt;
&lt;h2 id=&#34;example-shortcut-with-stages&#34;&gt;Example: shortcut with &lt;code&gt;stages&lt;/code&gt;&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;export const options = {
  stages: [
    { duration: &amp;#39;30s&amp;#39;, target: 20 },  // ramp up
    { duration: &amp;#39;1m&amp;#39;,  target: 20 },  // steady state
    { duration: &amp;#39;30s&amp;#39;, target: 0 },   // ramp down
  ],
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;example-explicit-scenario-with-ramping-vus&#34;&gt;Example: explicit scenario with &lt;code&gt;ramping-vus&lt;/code&gt;&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;export const options = {
  scenarios: {
    baseline: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        { duration: &amp;#39;30s&amp;#39;, target: 20 },
        { duration: &amp;#39;1m&amp;#39;,  target: 20 },
        { duration: &amp;#39;30s&amp;#39;, target: 0 },
      ],
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;choosing-your-vu-count&#34;&gt;Choosing your VU count&lt;/h2&gt;
&lt;p&gt;Match VUs to &lt;strong&gt;observed or expected concurrency&lt;/strong&gt; for the traffic slice you are baselining, not an arbitrary round number. If you do not yet have production metrics, start from staging access logs or product assumptions, then adjust after you see stable &lt;code&gt;http_req_duration&lt;/code&gt; and error rate in the steady-state window.&lt;/p&gt;
&lt;p&gt;If your profile uses &lt;a href=&#34;/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/&#34;&gt;&lt;code&gt;ramping-vus&lt;/code&gt;&lt;/a&gt;, the &lt;strong&gt;target&lt;/strong&gt; in each stage is the number of VUs k6 tries to schedule; combined with iteration time, that determines how much load you actually generate. For a deliberately constant &lt;strong&gt;request&lt;/strong&gt; rate instead, you would pick an arrival-rate executor; refer to &lt;a href=&#34;/docs/k6/latest/testing-guides/api-load-testing/#request-rate&#34;&gt;API load testing: request rate&lt;/a&gt;. This course stays on ramping VUs because it matches the baseline paths you run next.&lt;/p&gt;
&lt;p&gt;A baseline measures &lt;strong&gt;normal&lt;/strong&gt; behavior; deliberately exceeding your production concurrency belongs in stress or load-test scenarios covered in the &lt;a href=&#34;/docs/k6/latest/testing-guides/test-types/&#34;&gt;k6 test types&lt;/a&gt; guide after you have a baseline.&lt;/p&gt;
]]></content><description>&lt;h2 id="load-profile-shape">Load profile shape&lt;/h2>
&lt;p>A baseline load profile has three phases.&lt;/p>
&lt;p>&lt;img
class="lazyload d-inline-block"
data-src="designing-load-profile.svg"
alt="Load profile diagram showing ramp-up, steady state, and ramp-down"/>&lt;/p>
&lt;section class="expand-table-wrapper">&lt;div class="responsive-table-wrapper">
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Phase&lt;/th>
&lt;th>Purpose&lt;/th>
&lt;th>Duration&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Ramp-up&lt;/strong>&lt;/td>
&lt;td>Gradually increase VUs to avoid cold-start spikes&lt;/td>
&lt;td>30 seconds to 1 minute&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Steady state&lt;/strong>&lt;/td>
&lt;td>Hold at target load to collect stable metrics&lt;/td>
&lt;td>1-2 minutes minimum&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Ramp-down&lt;/strong>&lt;/td>
&lt;td>Reduce VUs back to zero for clean shutdown&lt;/td>
&lt;td>30 seconds&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/div>
&lt;/section>&lt;h2 id="scenarios-executors-and-stages">Scenarios, executors, and stages&lt;/h2>
&lt;p>k6 uses &lt;a href="/docs/k6/latest/using-k6/scenarios/">&lt;strong>scenarios&lt;/strong>&lt;/a> to describe how a test runs. Each scenario picks an &lt;a href="/docs/k6/latest/using-k6/scenarios/executors/">&lt;strong>executor&lt;/strong>&lt;/a> that schedules virtual users or iteration rate. The &lt;a href="/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/">&lt;strong>ramping-vus&lt;/strong>&lt;/a> executor changes the target number of VUs over time using a &lt;code>stages&lt;/code> array, which matches the ramp-up, steady-state, and ramp-down idea above.&lt;/p></description></item><item><title>Checks vs thresholds</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/18-checks-vs-thresholds/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/18-checks-vs-thresholds/</guid><content><![CDATA[&lt;h2 id=&#34;two-layers-of-validation&#34;&gt;Two layers of validation&lt;/h2&gt;
&lt;p&gt;&lt;img
  class=&#34;lazyload d-inline-block&#34;
  data-src=&#34;checks-vs-thresholds.svg&#34;
  alt=&#34;Checks vs thresholds side-by-side comparison&#34;/&gt;&lt;/p&gt;
&lt;h2 id=&#34;checks-per-request-correctness&#34;&gt;Checks: per-request correctness&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Checks&lt;/strong&gt; are assertions that validate each response. They don&amp;rsquo;t stop the test on failure.&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;check(res, {
  &amp;#39;status is 200&amp;#39;: (r) =&amp;gt; r.status === 200,
  &amp;#39;body is not empty&amp;#39;: (r) =&amp;gt; r.body.length &amp;gt; 0,
});&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;thresholds-whole-test-passfail&#34;&gt;Thresholds: whole-test pass/fail&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Thresholds&lt;/strong&gt; are pass/fail criteria for the entire test. They evaluate aggregate metrics.&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;thresholds: {
  http_req_duration: [&amp;#39;p(95)&amp;lt;500&amp;#39;],
  http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;],
  checks: [&amp;#39;rate&amp;gt;0.99&amp;#39;],
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;how-they-work-together&#34;&gt;How they work together&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Layer&lt;/th&gt;
              &lt;th&gt;Scope&lt;/th&gt;
              &lt;th&gt;On failure&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Checks&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Each request&lt;/td&gt;
              &lt;td&gt;Records failure, test continues&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Thresholds&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Entire test&lt;/td&gt;
              &lt;td&gt;Test exits with non-zero code (fails CI/CD)&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;]]></content><description>&lt;h2 id="two-layers-of-validation">Two layers of validation&lt;/h2>
&lt;p>&lt;img
class="lazyload d-inline-block"
data-src="checks-vs-thresholds.svg"
alt="Checks vs thresholds side-by-side comparison"/>&lt;/p>
&lt;h2 id="checks-per-request-correctness">Checks: per-request correctness&lt;/h2>
&lt;p>&lt;strong>Checks&lt;/strong> are assertions that validate each response. They don&amp;rsquo;t stop the test on failure.&lt;/p></description></item><item><title>From results to thresholds</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/19-results-to-thresholds/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/19-results-to-thresholds/</guid><content><![CDATA[&lt;h2 id=&#34;choosing-threshold-values&#34;&gt;Choosing threshold values&lt;/h2&gt;
&lt;p&gt;Start with your observed values and add headroom for normal variation:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Metric&lt;/th&gt;
              &lt;th&gt;Observed&lt;/th&gt;
              &lt;th&gt;Threshold&lt;/th&gt;
              &lt;th&gt;Headroom&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;p95 latency&lt;/td&gt;
              &lt;td&gt;320 ms&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;p(95)&amp;lt;500&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;~55% above observed&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Error rate&lt;/td&gt;
              &lt;td&gt;0%&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;rate&amp;lt;0.01&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Allows up to 1%&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Check pass rate&lt;/td&gt;
              &lt;td&gt;100%&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;rate&amp;gt;0.99&lt;/code&gt;&lt;/td&gt;
              &lt;td&gt;Allows up to 1% failure&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;trade-offs-in-threshold-decisions&#34;&gt;Trade-offs in threshold decisions&lt;/h2&gt;
&lt;p&gt;Threshold-setting involves judgment, not just formulas. Consider these trade-offs for your system:&lt;/p&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Decision&lt;/th&gt;
              &lt;th&gt;Tighter threshold&lt;/th&gt;
              &lt;th&gt;Looser threshold&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Headroom&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Catches small regressions early&lt;/td&gt;
              &lt;td&gt;Avoids false failures from normal variation&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;p95 vs p99&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;p95 reflects most users&amp;rsquo; experience&lt;/td&gt;
              &lt;td&gt;p99 catches tail latency affecting your slowest users&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;Error tolerance&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;rate&amp;lt;0.001&lt;/code&gt; is strict, good for payment flows&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;rate&amp;lt;0.01&lt;/code&gt; is practical for non-critical endpoints&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;A common starting approach: use p95 with 30-50% headroom for general APIs. Switch to p99 with tighter headroom for latency-sensitive paths like checkout or authentication.&lt;/p&gt;
]]></content><description>&lt;h2 id="choosing-threshold-values">Choosing threshold values&lt;/h2>
&lt;p>Start with your observed values and add headroom for normal variation:&lt;/p>
&lt;section class="expand-table-wrapper">&lt;div class="responsive-table-wrapper">
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Metric&lt;/th>
&lt;th>Observed&lt;/th>
&lt;th>Threshold&lt;/th>
&lt;th>Headroom&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>p95 latency&lt;/td>
&lt;td>320 ms&lt;/td>
&lt;td>&lt;code>p(95)&amp;lt;500&lt;/code>&lt;/td>
&lt;td>~55% above observed&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Error rate&lt;/td>
&lt;td>0%&lt;/td>
&lt;td>&lt;code>rate&amp;lt;0.01&lt;/code>&lt;/td>
&lt;td>Allows up to 1%&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Check pass rate&lt;/td>
&lt;td>100%&lt;/td>
&lt;td>&lt;code>rate&amp;gt;0.99&lt;/code>&lt;/td>
&lt;td>Allows up to 1% failure&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/div>
&lt;/section>&lt;h2 id="trade-offs-in-threshold-decisions">Trade-offs in threshold decisions&lt;/h2>
&lt;p>Threshold-setting involves judgment, not just formulas. Consider these trade-offs for your system:&lt;/p></description></item><item><title>When thresholds fail</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/19b-when-thresholds-fail/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/19b-when-thresholds-fail/</guid><content><![CDATA[&lt;h2 id=&#34;failure-signals-in-the-terminal&#34;&gt;Failure signals in the terminal&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;✓&lt;/strong&gt; passed that line; &lt;strong&gt;✗&lt;/strong&gt; failed the threshold on that line.&lt;/p&gt;
&lt;p&gt;When all thresholds pass:&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;✓ http_req_duration..............: avg=186ms  p(95)=312ms
✓ http_req_failed................: 0.00%
✓ checks.........................: 100.00%&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;When a threshold fails:&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;✗ http_req_duration..............: avg=743ms  p(95)=1247ms
                                   ✗ { p(95)&amp;lt;500 }
✓ http_req_failed................: 0.42%
✓ checks.........................: 99.80%&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;exit-codes-and-early-stop&#34;&gt;Exit codes and early stop&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Exit code&lt;/th&gt;
              &lt;th&gt;Meaning&lt;/th&gt;
              &lt;th&gt;CI/CD behavior&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;All thresholds passed&lt;/td&gt;
              &lt;td&gt;Pipeline continues&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;99&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;One or more thresholds breached&lt;/td&gt;
              &lt;td&gt;Pipeline fails the step&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;Add &lt;code&gt;abortOnFail&lt;/code&gt; to end the run immediately on a critical breach:&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;thresholds: {
  http_req_duration: [
    { threshold: &amp;#39;p(95)&amp;lt;500&amp;#39;, abortOnFail: true },
  ],
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;example-regression-caught-in-ci&#34;&gt;Example: regression caught in CI&lt;/h2&gt;
&lt;p&gt;A change ships with passing unit tests; the baseline gate runs last. &lt;strong&gt;p(95)=683ms&lt;/strong&gt; vs &lt;strong&gt;p(95)&amp;lt;500&lt;/strong&gt; → &lt;strong&gt;exit 99&lt;/strong&gt;, deploy blocked.&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;running (2m01.3s), 00/20 VUs, 1847 complete iterations
     ✓ status is 200
     ✓ body is not empty

     ✗ http_req_duration..............: avg=512ms  p(95)=683ms
                                        ✗ { p(95)&amp;lt;500 }
     ✓ http_req_failed................: 0.00%
     ✓ checks.........................: 100.00%

ERRO threshold breached: http_req_duration p(95)&amp;lt;500, got 683.21ms&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;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Metric&lt;/th&gt;
              &lt;th&gt;Last passing&lt;/th&gt;
              &lt;th&gt;This run&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;p95&lt;/td&gt;
              &lt;td&gt;318 ms&lt;/td&gt;
              &lt;td&gt;683 ms&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Throughput&lt;/td&gt;
              &lt;td&gt;15.3 requests per second (RPS)&lt;/td&gt;
              &lt;td&gt;15.1 RPS (similar)&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Errors&lt;/td&gt;
              &lt;td&gt;0%&lt;/td&gt;
              &lt;td&gt;0%&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;p&gt;Latency jumps while throughput is flat usually means &lt;strong&gt;per-request work&lt;/strong&gt; got heavier (for example synchronous database work). Fix the hot path, re-run, pipeline goes green.&lt;/p&gt;
]]></content><description>&lt;h2 id="failure-signals-in-the-terminal">Failure signals in the terminal&lt;/h2>
&lt;p>&lt;strong>✓&lt;/strong> passed that line; &lt;strong>✗&lt;/strong> failed the threshold on that line.&lt;/p>
&lt;p>When all thresholds pass:&lt;/p>
&lt;div class="code-snippet ">&lt;div class="lang-toolbar">
&lt;span class="lang-toolbar__item lang-toolbar__item-active">text&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-text">✓ http_req_duration..............: avg=186ms p(95)=312ms
✓ http_req_failed................: 0.00%
✓ checks.........................: 100.00%&lt;/code>&lt;/pre>
&lt;/div>
&lt;/div>
&lt;p>When a threshold fails:&lt;/p></description></item><item><title>Baseline learning path</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/20-baseline-path/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/20-baseline-path/</guid><content><![CDATA[&lt;h2 id=&#34;learning-path-establish-a-performance-baseline-with-k6&#34;&gt;Learning path: Establish a performance baseline with k6&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Step&lt;/th&gt;
              &lt;th&gt;What you&amp;rsquo;ll do&lt;/th&gt;
              &lt;th&gt;Outcome&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;1. Design load profile&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Configure ramp-up, steady state, and ramp-down&lt;/td&gt;
              &lt;td&gt;Realistic traffic shape&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;2. Add checks&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Assertions on response correctness&lt;/td&gt;
              &lt;td&gt;Per-request validation&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;3. Observe&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Run without thresholds&lt;/td&gt;
              &lt;td&gt;Measured p95, errors, throughput&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;4. Set thresholds&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Pass or fail from observed values plus headroom&lt;/td&gt;
              &lt;td&gt;Quality gate in the script&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;5. Validate&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Re-run until stable&lt;/td&gt;
              &lt;td&gt;Trusted baseline&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;&lt;strong&gt;6. Review in Cloud&lt;/strong&gt;&lt;/td&gt;
              &lt;td&gt;Dashboards in Grafana Cloud k6&lt;/td&gt;
              &lt;td&gt;History and comparison&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;context&#34;&gt;Context&lt;/h2&gt;
&lt;p&gt;Extends the Module 2 script and Cloud setup, with no restart from zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optional — help with the script:&lt;/strong&gt; Use &lt;strong&gt;Grafana Assistant&lt;/strong&gt; in &lt;strong&gt;k6 Script Authoring&lt;/strong&gt; mode in Grafana Cloud to refine stages, checks, or thresholds. Refer to &lt;a href=&#34;/docs/grafana-cloud/testing/k6/author-run/k6-script-authoring-mode/&#34;&gt;Use k6 Script Authoring mode&lt;/a&gt; and the &lt;a href=&#34;../../01-intro/06-prerequisites/&#34;&gt;Prerequisites&lt;/a&gt; slide for access notes.&lt;/p&gt;









  
    
  
  
&lt;div class=&#34;learning-path-card&#34;&gt;
  




  
  
    
  


&lt;div class=&#34;pathway-row__label mb-1&#34;&gt;
  
  &lt;svg width=&#34;40&#34; height=&#34;40&#34; viewBox=&#34;0 0 40 40&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;rect x=&#34;0.5&#34; y=&#34;0.5&#34; width=&#34;39&#34; height=&#34;39&#34; rx=&#34;3.5&#34; fill=&#34;white&#34; stroke=&#34;#D8D8DF&#34;&gt;&lt;/rect&gt;&lt;path d=&#34;M8 20H14C16.5 20 18.5 18 18.5 15.5V12&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M8 20H14C16.5 20 18.5 22 18.5 24.5V28&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M14 20H32&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;/path&gt;&lt;circle cx=&#34;18.5&#34; cy=&#34;12&#34; r=&#34;2&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; fill=&#34;white&#34;&gt;&lt;/circle&gt;&lt;circle cx=&#34;18.5&#34; cy=&#34;28&#34; r=&#34;2&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; fill=&#34;white&#34;&gt;&lt;/circle&gt;&lt;path d=&#34;M29 17L32 20L29 23&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;/path&gt;&lt;/svg&gt;

  Learning path
&lt;/div&gt;

&lt;h4&gt;Establish a k6 baseline&lt;/h4&gt;
&lt;p&gt;Welcome to the Grafana learning path that shows you how to establish a performance baseline with k6, from understanding key metrics to enforcing thresholds and sharing results.&lt;/p&gt;

&lt;div class=&#34;d-sm-flex gap-half mb-2&#34;&gt;
  &lt;div class=&#34;d-flex align-items-center gap-half text-gray-12 mt-half body-small&#34;&gt;
    &lt;div class=&#34;journey-list__icon&#34;&gt;
  &lt;svg width=&#34;24&#34; height=&#34;24&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M11.9995 22.5039C17.7985 22.5039 22.4995 17.8029 22.4995 12.0039C22.4995 6.20492 17.7985 1.50391 11.9995 1.50391C6.20052 1.50391 1.49951 6.20492 1.49951 12.0039C1.49951 17.8029 6.20052 22.5039 11.9995 22.5039Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M11.9995 12.0039V8.25391&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M11.9995 12.0078L16.6865 16.6958&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;
&lt;/div&gt;
    &lt;span&gt;19 min&lt;/span&gt;
  &lt;/div&gt;
  
  &lt;div class=&#34;d-flex align-items-center gap-half text-gray-12 mt-half body-small&#34;&gt;
    &lt;div class=&#34;journey-list__icon&#34;&gt;
  &lt;svg width=&#34;24&#34; height=&#34;25&#34; viewBox=&#34;0 0 24 25&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M0.75 9.83984C0.75 7.6307 2.54086 5.83984 4.75 5.83984H19.25C21.4591 5.83984 23.25 7.6307 23.25 9.83984V19.1198C23.25 21.329 21.4591 23.1198 19.25 23.1198H4.75C2.54086 23.1198 0.75 21.329 0.75 19.1198V9.83984Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M14.25 1.52344H9.75C8.92157 1.52344 8.25 2.16815 8.25 2.96344V5.84344H15.75V2.96344C15.75 2.16815 15.0784 1.52344 14.25 1.52344Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M12 15.923C12.8284 15.923 13.5 15.2783 13.5 14.483C13.5 13.6877 12.8284 13.043 12 13.043C11.1716 13.043 10.5 13.6877 10.5 14.483C10.5 15.2783 11.1716 15.923 12 15.923Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M13.2742 8.91315L13.7162 10.309C13.8671 10.7897 14.3806 11.0756 14.8902 10.9628L16.3622 10.6354C16.9349 10.5115 17.5249 10.7602 17.8175 11.2488C18.11 11.7374 18.037 12.3519 17.6372 12.7647L16.6062 13.8312C16.2493 14.1997 16.2493 14.7703 16.6062 15.1388L17.6372 16.2053C18.0379 16.6179 18.1115 17.2331 17.8188 17.7222C17.526 18.2113 16.9353 18.4601 16.3622 18.3356L14.8902 18.0082C14.3806 17.8953 13.8671 18.1812 13.7162 18.662L13.2742 20.0559C13.1055 20.5961 12.5877 20.9661 12.0002 20.9661C11.4128 20.9661 10.8949 20.5961 10.7262 20.0559L10.2842 18.661C10.1333 18.1803 9.61982 17.8944 9.11021 18.0072L7.63821 18.3346C7.06469 18.4597 6.47325 18.2109 6.18034 17.7213C5.88742 17.2317 5.96161 16.6159 6.36321 16.2034L7.39421 15.1368C7.75116 14.7684 7.75116 14.1978 7.39421 13.8293L6.36321 12.7628C5.96346 12.35 5.89039 11.7354 6.18296 11.2468C6.47553 10.7582 7.06551 10.5096 7.63821 10.6335L9.11021 10.9608C9.61923 11.0739 10.1324 10.7889 10.2842 10.309L10.7262 8.91507C10.8944 8.37473 11.412 8.00435 11.9995 8.00391C12.5869 8.00346 13.1051 8.37307 13.2742 8.91315V8.91315Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;
&lt;/div&gt;
    &lt;span&gt;Beginner&lt;/span&gt;
  &lt;/div&gt;
  
  
  &lt;div class=&#34;d-flex align-items-center gap-half text-gray-12 mt-half body-small&#34;&gt;
    &lt;div class=&#34;journey-list__icon&#34;&gt;
  &lt;svg width=&#34;24&#34; height=&#34;24&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
  &lt;path fill-rule=&#34;evenodd&#34; clip-rule=&#34;evenodd&#34; d=&#34;M0.75 2.75C0.75 1.64543 1.64543 0.75 2.75 0.75H21.25C22.3546 0.75 23.25 1.64543 23.25 2.75V21.25C23.25 22.3546 22.3546 23.25 21.25 23.25H2.75C1.64543 23.25 0.75 22.3546 0.75 21.25V2.75Z&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M12 4.5L7.5 10.5L4.5 7.5&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M14.25 8.25H18.75&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M12 13.5L7.5 19.5L4.5 16.5&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
  &lt;path d=&#34;M14.25 17.25H18.75&#34; stroke=&#34;#FF671D&#34; stroke-width=&#34;1.5&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;/&gt;
&lt;/svg&gt;
&lt;/div&gt;
    &lt;span&gt;Docs &amp;amp; blog posts&lt;/span&gt;
  &lt;/div&gt;
  
&lt;/div&gt;







  


&lt;div class=&#34;orange-outline-list br-12 border-color-orange-flat border-width-2 p-1-5 pb-1&#34; x3-data=&#34;selectStack(&#39;/docs/learning-paths/establish-k6-baseline&#39;)&#34;&gt;
  &lt;div class=&#34;icon-heading d-flex&#34;&gt;
    &lt;div class=&#34;icon-heading__container&#34;&gt;
  &lt;svg width=&#34;30&#34; height=&#34;30&#34; viewBox=&#34;0 0 25 26&#34; fill=&#34;none&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
  &lt;path d=&#34;M16.1401 14.4402C16.2141 14.4402 16.2852 14.4101 16.3373 14.3581C16.5355 14.1569 21.1904 9.39886 21.1904 5.0513C21.1904 2.26537 18.924 0 16.1391 0C13.3541 0 11.0878 2.26537 11.0878 5.0513C11.0878 9.39886 15.7427 14.1569 15.9419 14.3581C15.9939 14.4111 16.065 14.4402 16.1401 14.4402ZM13.5814 5.0513C13.5814 3.63882 14.7266 2.49262 16.1401 2.49262C17.5536 2.49262 18.6978 3.63781 18.6978 5.0513C18.6978 6.46478 17.5526 7.60999 16.1401 7.60999C14.7276 7.60999 13.5814 6.46478 13.5814 5.0513Z&#34; fill=&#34;#FF671D&#34;/&gt;
  &lt;path d=&#34;M24.9034 21.9305C24.0595 18.9113 17.9561 17.4147 12.5704 16.0933C9.54023 15.3496 5.76827 14.4246 5.73524 13.6037C5.72823 13.4225 5.97949 12.7398 9.52922 11.5516C9.80551 11.4585 9.96668 11.1842 9.91262 10.8989C9.85856 10.6136 9.60229 10.4164 9.318 10.4304C4.13956 10.6807 0.501743 12.1602 0.0482666 14.1993C-0.172966 15.1944 0.26149 16.749 3.58398 18.5009L4.29773 18.8763C6.54509 20.0545 8.16879 20.9064 8.1808 21.6992C8.19482 22.6502 5.93745 24.0507 3.72713 25.296C3.58398 25.3761 3.5139 25.5433 3.55495 25.7024C3.59699 25.8616 3.74014 25.9717 3.90431 25.9717H23.0354C23.1315 25.9717 23.2226 25.9337 23.2907 25.8656C24.6971 24.4581 25.2397 23.1347 24.9034 21.9305Z&#34; fill=&#34;#FBC55A&#34;/&gt;
&lt;/svg&gt;
&lt;/div&gt;
    &lt;div class=&#34;no-anchor-heading&#34;&gt;
      &lt;h4&gt;Open in Grafana Cloud&lt;/h4&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&#34;mt-1&#34;&gt;
    &lt;p class=&#34;mb-1 maxw-650&#34;&gt;
      
        Complete this learning path directly in your Grafana Cloud stack with an interactive learning experience.
      
    &lt;/p&gt;
    &lt;div class=&#34;d-flex column-gap-1 justify-content-end&#34;&gt;
      &lt;a
        x3-bind:href=&#34;launchUrl&#34;
        class=&#34;btn btn--primary br-8&#34;
        target=&#34;_blank&#34;
        x3-on:click=&#34;trackPathfinderClick(&#39;establish-k6-baseline&#39;, &#39;Establish a k6 baseline&#39;)&#34;&gt;
        Open in Grafana Cloud
      &lt;/a&gt;
      
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&#34;mt-1&#34;&gt;
  &lt;a
    href=&#34;/docs/learning-paths/establish-k6-baseline/&#34;
    target=&#34;_blank&#34;
    rel=&#34;noopener noreferrer&#34;
    class=&#34;btn btn--outline arrow w-100p br-8&#34;
    x3-on:click=&#34;$dispatch(&#39;track-view-on-website&#39;, {
      pathId: &#39;establish-k6-baseline&#39;,
      pathTitle: &#39;Establish a k6 baseline&#39;
    })&#34;&gt;
    View on website
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;



]]></content><description>&lt;h2 id="learning-path-establish-a-performance-baseline-with-k6">Learning path: Establish a performance baseline with k6&lt;/h2>
&lt;section class="expand-table-wrapper">&lt;div class="responsive-table-wrapper">
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Step&lt;/th>
&lt;th>What you&amp;rsquo;ll do&lt;/th>
&lt;th>Outcome&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>1. Design load profile&lt;/strong>&lt;/td>
&lt;td>Configure ramp-up, steady state, and ramp-down&lt;/td>
&lt;td>Realistic traffic shape&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>2. Add checks&lt;/strong>&lt;/td>
&lt;td>Assertions on response correctness&lt;/td>
&lt;td>Per-request validation&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>3. Observe&lt;/strong>&lt;/td>
&lt;td>Run without thresholds&lt;/td>
&lt;td>Measured p95, errors, throughput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>4. Set thresholds&lt;/strong>&lt;/td>
&lt;td>Pass or fail from observed values plus headroom&lt;/td>
&lt;td>Quality gate in the script&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>5. Validate&lt;/strong>&lt;/td>
&lt;td>Re-run until stable&lt;/td>
&lt;td>Trusted baseline&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>6. Review in Cloud&lt;/strong>&lt;/td>
&lt;td>Dashboards in Grafana Cloud k6&lt;/td>
&lt;td>History and comparison&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/div>
&lt;/section>&lt;h2 id="context">Context&lt;/h2>
&lt;p>Extends the Module 2 script and Cloud setup, with no restart from zero.&lt;/p></description></item><item><title>Baseline complete</title><link>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/21-baseline-debrief/</link><pubDate>Fri, 05 Jun 2026 12:46:32 -0400</pubDate><guid>https://grafana.com/docs/learning-hub/k6-performance-testing/03-establishing-a-baseline/21-baseline-debrief/</guid><content><![CDATA[&lt;h2 id=&#34;baseline-complete&#34;&gt;Baseline complete!&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What you accomplished:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Designed a realistic load profile with ramp-up, steady state, and ramp-down&lt;/li&gt;
&lt;li&gt;Added checks that validate response correctness on every request&lt;/li&gt;
&lt;li&gt;Ran a test to observe actual p95 latency, throughput, and error rate&lt;/li&gt;
&lt;li&gt;Set thresholds based on measured values with appropriate headroom&lt;/li&gt;
&lt;li&gt;Validated that your baseline test passes consistently&lt;/li&gt;
&lt;li&gt;Stored results in Grafana Cloud k6 for historical comparison&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;skills-unlocked&#34;&gt;Skills unlocked&lt;/h2&gt;
&lt;section class=&#34;expand-table-wrapper&#34;&gt;&lt;div class=&#34;responsive-table-wrapper&#34;&gt;
    &lt;table&gt;
      &lt;thead&gt;
          &lt;tr&gt;
              &lt;th&gt;Skill&lt;/th&gt;
              &lt;th&gt;You can now&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
          &lt;tr&gt;
              &lt;td&gt;Load profile design&lt;/td&gt;
              &lt;td&gt;Create realistic traffic patterns with ramping VUs&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Correctness checks&lt;/td&gt;
              &lt;td&gt;Validate responses are correct, not just fast&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Threshold setting&lt;/td&gt;
              &lt;td&gt;Turn observed metrics into automated pass/fail criteria&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Baseline management&lt;/td&gt;
              &lt;td&gt;Compare results over time and detect regressions&lt;/td&gt;
          &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/div&gt;
&lt;/section&gt;&lt;h2 id=&#34;examine-your-baseline&#34;&gt;Examine your baseline&lt;/h2&gt;
&lt;p&gt;Look at your baseline results in Grafana Cloud k6 and consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Threshold headroom.&lt;/strong&gt; How much buffer did you leave above your observed p95? Tighter thresholds catch regressions sooner. Loose thresholds avoid false failures from normal jitter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steady state stability.&lt;/strong&gt; Were metrics steady during steady state, or did they drift? Drift can mean warm-up, a slow leak, or shifting dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check failures.&lt;/strong&gt; Did any checks fail during the baseline? Decide whether that should change how you threshold the &lt;code&gt;checks&lt;/code&gt; metric.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confidence.&lt;/strong&gt; If you ran this test three times, would you expect the same outcome? If not, list what might vary (data, time of day, cold caches, shared environments).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You will reuse this same review habit after every code change or infrastructure update.&lt;/p&gt;
&lt;h2 id=&#34;whats-next&#34;&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;Your baseline answers &amp;ldquo;what does normal look like?&amp;rdquo; In the wrap-up module, &lt;strong&gt;&lt;a href=&#34;../../04-wrap-up/23-transfer-exercise/&#34;&gt;Apply the pattern to your own service&lt;/a&gt;&lt;/strong&gt; is a short transfer checklist to run the same workflow on a URL your team owns (still on non-production).&lt;/p&gt;
&lt;p&gt;After that, the next question is what happens when things are not normal. Stress, spike, and soak testing are the usual follow-on topics; use the &lt;a href=&#34;/docs/k6/latest/testing-guides/test-types/&#34;&gt;k6 test types guide&lt;/a&gt; when you are ready to design those runs.&lt;/p&gt;
]]></content><description>&lt;h2 id="baseline-complete">Baseline complete!&lt;/h2>
&lt;p>&lt;strong>What you accomplished:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Designed a realistic load profile with ramp-up, steady state, and ramp-down&lt;/li>
&lt;li>Added checks that validate response correctness on every request&lt;/li>
&lt;li>Ran a test to observe actual p95 latency, throughput, and error rate&lt;/li>
&lt;li>Set thresholds based on measured values with appropriate headroom&lt;/li>
&lt;li>Validated that your baseline test passes consistently&lt;/li>
&lt;li>Stored results in Grafana Cloud k6 for historical comparison&lt;/li>
&lt;/ul>
&lt;h2 id="skills-unlocked">Skills unlocked&lt;/h2>
&lt;section class="expand-table-wrapper">&lt;div class="responsive-table-wrapper">
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Skill&lt;/th>
&lt;th>You can now&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Load profile design&lt;/td>
&lt;td>Create realistic traffic patterns with ramping VUs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Correctness checks&lt;/td>
&lt;td>Validate responses are correct, not just fast&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Threshold setting&lt;/td>
&lt;td>Turn observed metrics into automated pass/fail criteria&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Baseline management&lt;/td>
&lt;td>Compare results over time and detect regressions&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;/div>
&lt;/section>&lt;h2 id="examine-your-baseline">Examine your baseline&lt;/h2>
&lt;p>Look at your baseline results in Grafana Cloud k6 and consider:&lt;/p></description></item></channel></rss>