---
title: "Designing a realistic load profile | Grafana Labs"
description: "Ramp-up, steady state, and ramp-down for realistic traffic simulation"
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

## Load profile shape

A baseline load profile has three phases.

| Phase            | Purpose                                           | Duration               |
|------------------|---------------------------------------------------|------------------------|
| **Ramp-up**      | Gradually increase VUs to avoid cold-start spikes | 30 seconds to 1 minute |
| **Steady state** | Hold at target load to collect stable metrics     | 1-2 minutes minimum    |
| **Ramp-down**    | Reduce VUs back to zero for clean shutdown        | 30 seconds             |

## Scenarios, executors, and stages

k6 uses [**scenarios**](/docs/k6/latest/using-k6/scenarios/) to describe how a test runs. Each scenario picks an [**executor**](/docs/k6/latest/using-k6/scenarios/executors/) that schedules virtual users or iteration rate. The [**ramping-vus**](/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/) executor changes the target number of VUs over time using a `stages` array, which matches the ramp-up, steady-state, and ramp-down idea above.

Putting `stages` on the root `options` 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 `scenarios` object explicitly instead.

## Example: shortcut with `stages`

JavaScript ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```javascript
export const options = {
  stages: [
    { duration: '30s', target: 20 },  // ramp up
    { duration: '1m',  target: 20 },  // steady state
    { duration: '30s', target: 0 },   // ramp down
  ],
};
```

## Example: explicit scenario with `ramping-vus`

JavaScript ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```javascript
export const options = {
  scenarios: {
    baseline: {
      executor: 'ramping-vus',
      stages: [
        { duration: '30s', target: 20 },
        { duration: '1m',  target: 20 },
        { duration: '30s', target: 0 },
      ],
    },
  },
};
```

## Choosing your VU count

Match VUs to **observed or expected concurrency** 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 `http_req_duration` and error rate in the steady-state window.

If your profile uses [`ramping-vus`](/docs/k6/latest/using-k6/scenarios/executors/ramping-vus/), the **target** 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 **request** rate instead, you would pick an arrival-rate executor; refer to [API load testing: request rate](/docs/k6/latest/testing-guides/api-load-testing/#request-rate). This course stays on ramping VUs because it matches the baseline paths you run next.

A baseline measures **normal** behavior; deliberately exceeding your production concurrency belongs in stress or load-test scenarios covered in the [k6 test types](/docs/k6/latest/testing-guides/test-types/) guide after you have a baseline.
