Design a soak profile

The k6 Soak testing guide reuses an average-load script and lengthens the plateau. The shape is ramp up, hold at average load, ramp down. Duration on the plateau is what changes between average-load and soak work.

If you use Grafana Cloud with Grafana Assistant enabled, refer to Use k6 Script Authoring mode to draft or refine a script from a description. The steps below build soak.js in your editor so you can follow the profile structure line by line.

To design a soak profile, complete the following steps:

  1. Create soak.js and add imports:

    JavaScript
    import http from 'k6/http';
    import { check, sleep } from 'k6';
  2. Define stages and thresholds.

    Set target to the VU count from your baseline or average-load test. While learning this path, use a 30-minute plateau; extend the middle stage for production soaks (for example 2 to 8 hours):

    JavaScript
    export const options = {
      stages: [
        { duration: '2m', target: 15 }, // ramp up to average-load level
        { duration: '30m', target: 15 }, // soak plateau (learning duration)
        { duration: '2m', target: 0 }, // ramp down
      ],
      thresholds: {
        http_req_duration: ['p(95)<500'],
        http_req_failed: ['rate<0.01'],
      },
    };

    If your baseline test runs at 20 VUs, 15 VUs is a moderate plateau below peak. Adjust target to match the average-load level you measured. Use http_req_failed for pass/fail on HTTP errors; keep checks in the default function for summary visibility. Thresholds are tighter than in a stress test because load is moderate—a breach during the plateau often points to time-dependent degradation rather than overload.

  3. Add the default function with the same checks as your baseline test:

    JavaScript
    export default function () {
      const res = http.get('https://quickpizza.grafana.com');
    
      check(res, {
        'status is 200': (r) => r.status === 200,
        'response body is not empty': (r) => r.body && r.body.length > 0,
      });
    
      sleep(1);
    }

    Replace the URL with the endpoint you used in baseline testing. When a request fails (for example a connection reset), k6 may not set body. The r.body && guard returns false for that check instead of throwing a script error.

  4. Save soak.js. Your complete file combines the options block and default function:

    JavaScript
    import http from 'k6/http';
    import { check, sleep } from 'k6';
    
    export const options = {
      stages: [
        { duration: '2m', target: 15 },
        { duration: '30m', target: 15 },
        { duration: '2m', target: 0 },
      ],
      thresholds: {
        http_req_duration: ['p(95)<500'],
        http_req_failed: ['rate<0.01'],
      },
    };
    
    export default function () {
      const res = http.get('https://quickpizza.grafana.com');
    
      check(res, {
        'status is 200': (r) => r.status === 200,
        'response body is not empty': (r) => r.body && r.body.length > 0,
      });
    
      sleep(1);
    }

    The 30m plateau keeps this path practical for learning. Production soaks commonly use 3, 4, 8, 12, or 24 hours on the middle stage, as noted in the soak test-type guide. Extend duration after you confirm the workflow end to end.

In the next milestone, you configure cloud streaming and degradation thresholds so you can observe the run while it is in progress.


page 3 of 8