> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/grafana/k6/llms.txt
> Use this file to discover all available pages before exploring further.

# Scenarios

> Advanced test execution with k6 scenarios and executors

# Scenarios

Scenarios provide fine-grained control over how k6 executes your test. They allow you to model complex user behavior patterns, run different workloads in parallel, and precisely control VU execution.

## Why Use Scenarios?

Scenarios are more powerful than simple `vus`, `duration`, or `stages` options:

* **Multiple workflows**: Run different test functions simultaneously
* **Different load patterns**: Combine constant load, ramping, and spike patterns
* **Precise VU control**: Control exactly how VUs execute iterations
* **Per-scenario configuration**: Set different options for each scenario
* **Advanced metrics**: Get per-scenario metrics and tags

## Basic Scenario Structure

```javascript theme={null}
import http from 'k6/http';

export let options = {
  scenarios: {
    my_scenario: {                    // Scenario name
      executor: 'constant-vus',       // Executor type
      vus: 10,                        // Executor-specific options
      duration: '30s',
    },
  },
};

export default function() {
  http.get('https://quickpizza.grafana.com');
}
```

## Executors

Executors define how VUs are scheduled and iterations are executed. k6 provides several executor types:

### Constant VUs

Maintains a constant number of VUs for a duration.

```javascript theme={null}
export let options = {
  scenarios: {
    constant_load: {
      executor: 'constant-vus',
      vus: 10,
      duration: '1m',
    },
  },
};
```

**Use case**: Steady-state load testing

### Ramping VUs

Gradually ramps VUs up and down.

```javascript theme={null}
export let options = {
  scenarios: {
    ramping_load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '30s', target: 10 },
        { duration: '1m', target: 10 },
        { duration: '30s', target: 0 },
      ],
      gracefulRampDown: '30s',
    },
  },
};
```

**Use case**: Gradually increasing load, soak testing

### Constant Arrival Rate

Starts iterations at a constant rate, adding VUs as needed.

```javascript theme={null}
export let options = {
  scenarios: {
    constant_rate: {
      executor: 'constant-arrival-rate',
      rate: 30,              // 30 iterations per timeUnit
      timeUnit: '1s',        // per second
      duration: '1m',
      preAllocatedVUs: 10,   // Pre-allocated VUs
      maxVUs: 50,            // Maximum VUs to allocate
    },
  },
};
```

**Use case**: Testing system under constant request rate, measuring latency under load

<Note>
  Constant arrival rate focuses on iteration starts per time unit, not concurrent VUs. k6 will add VUs as needed to maintain the rate.
</Note>

### Ramping Arrival Rate

Gradually increases or decreases the iteration start rate.

```javascript theme={null}
export let options = {
  scenarios: {
    ramping_rate: {
      executor: 'ramping-arrival-rate',
      startRate: 10,
      timeUnit: '1s',
      preAllocatedVUs: 20,
      maxVUs: 100,
      stages: [
        { duration: '30s', target: 10 },   // Start at 10 iters/s
        { duration: '1m', target: 50 },    // Ramp to 50 iters/s
        { duration: '30s', target: 10 },   // Ramp down to 10 iters/s
      ],
    },
  },
};
```

**Use case**: Gradually increasing throughput testing

### Shared Iterations

Shares a fixed number of iterations among VUs.

```javascript theme={null}
export let options = {
  scenarios: {
    shared_iters: {
      executor: 'shared-iterations',
      vus: 10,
      iterations: 100,       // Total iterations shared across VUs
      maxDuration: '30s',
    },
  },
};
```

**Use case**: Completing a specific number of test iterations as quickly as possible

### Per-VU Iterations

Each VU executes a specific number of iterations.

```javascript theme={null}
export let options = {
  scenarios: {
    per_vu_iters: {
      executor: 'per-vu-iterations',
      vus: 10,
      iterations: 10,        // Each VU runs 10 iterations
      maxDuration: '30s',
    },
  },
};
```

**Use case**: Testing with a precise total number of iterations (vus × iterations)

### Externally Controlled

Control execution externally via k6's REST API.

```javascript theme={null}
export let options = {
  scenarios: {
    external: {
      executor: 'externally-controlled',
      vus: 10,
      maxVUs: 50,
      duration: '5m',
    },
  },
};
```

**Use case**: Dynamic control of VUs during test execution

## Multiple Scenarios

Run different test functions with different load patterns:

```javascript theme={null}
import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    messages: {
      executor: 'constant-vus',
      exec: 'messages',         // Function to execute
      vus: 1,
      duration: '2s',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
    news: {
      executor: 'per-vu-iterations',
      exec: 'news',             // Different function
      vus: 1,
      iterations: 2,
      maxDuration: '5s',
      options: {
        browser: {
          type: 'chromium',
        },
      },
    },
  },
  thresholds: {
    browser_web_vital_fcp: ['max < 5000'],
    checks: ["rate==1.0"]
  }
}

export async function messages() {
  const page = await browser.newPage();
  try {
    await page.goto('https://quickpizza.grafana.com/my_messages.php', { 
      waitUntil: 'networkidle' 
    });
  } finally {
    await page.close();
  }
}

export async function news() {
  const page = await browser.newPage();
  try {
    await page.goto('https://quickpizza.grafana.com/news.php', { 
      waitUntil: 'networkidle' 
    });
  } finally {
    await page.close();
  }
}
```

## Scenario Configuration Options

### Common Options

All scenarios support these options:

```javascript theme={null}
export let options = {
  scenarios: {
    my_scenario: {
      executor: 'constant-vus',
      
      // Execution control
      startTime: '10s',              // Delay start by 10s
      gracefulStop: '30s',           // Time to finish iterations after duration
      
      // Function to execute
      exec: 'myFunction',            // Default: 'default'
      
      // Environment variables
      env: {
        MY_VAR: 'value',
      },
      
      // Tags for this scenario's metrics
      tags: {
        scenario_type: 'api',
        team: 'backend',
      },
    },
  },
};

export function myFunction() {
  // Custom test logic
}
```

### Staggered Start Times

Start scenarios at different times:

```javascript theme={null}
export let options = {
  scenarios: {
    warmup: {
      executor: 'constant-vus',
      vus: 5,
      duration: '1m',
      startTime: '0s',             // Start immediately
    },
    main_load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 50 },
      ],
      startTime: '1m',             // Start after warmup
    },
  },
};
```

## Scenario Tags and Metrics

Each scenario automatically gets tagged:

```javascript theme={null}
import http from 'k6/http';
import { check } from 'k6';

export let options = {
  scenarios: {
    api_test: {
      executor: 'constant-vus',
      vus: 10,
      duration: '30s',
      tags: {
        test_type: 'api',
        version: 'v2',
      },
    },
  },
  thresholds: {
    // Threshold for specific scenario
    'http_req_duration{scenario:api_test}': ['p(95)<500'],
  },
};

export default function() {
  http.get('https://quickpizza.grafana.com/api/menu');
}
```

## Graceful Stop

Control how iterations finish at the end:

```javascript theme={null}
export let options = {
  scenarios: {
    my_scenario: {
      executor: 'constant-vus',
      vus: 10,
      duration: '1m',
      gracefulStop: '30s',    // Wait up to 30s for iterations to finish
    },
  },
};
```

<Warning>
  If iterations don't complete within the gracefulStop period, they are forcefully terminated.
</Warning>

## Scenario Examples

<Tabs>
  <Tab title="Spike Test">
    ```javascript theme={null}
    export let options = {
      scenarios: {
        spike: {
          executor: 'ramping-vus',
          startVUs: 0,
          stages: [
            { duration: '10s', target: 10 },   // Normal load
            { duration: '10s', target: 100 },  // Spike!
            { duration: '10s', target: 10 },   // Back to normal
          ],
          gracefulRampDown: '10s',
        },
      },
    };
    ```
  </Tab>

  <Tab title="Stress Test">
    ```javascript theme={null}
    export let options = {
      scenarios: {
        stress: {
          executor: 'ramping-arrival-rate',
          startRate: 10,
          timeUnit: '1s',
          preAllocatedVUs: 50,
          maxVUs: 500,
          stages: [
            { duration: '2m', target: 10 },    // Normal
            { duration: '5m', target: 50 },    // Increase
            { duration: '5m', target: 100 },   // High load
            { duration: '5m', target: 200 },   // Very high
            { duration: '2m', target: 10 },    // Recovery
          ],
        },
      },
    };
    ```
  </Tab>

  <Tab title="Soak Test">
    ```javascript theme={null}
    export let options = {
      scenarios: {
        soak: {
          executor: 'constant-vus',
          vus: 50,
          duration: '4h',              // Long duration
        },
      },
    };
    ```
  </Tab>

  <Tab title="Mixed Workload">
    ```javascript theme={null}
    export let options = {
      scenarios: {
        read_heavy: {
          executor: 'constant-arrival-rate',
          exec: 'readData',
          rate: 100,
          timeUnit: '1s',
          duration: '5m',
          preAllocatedVUs: 20,
          maxVUs: 100,
        },
        write_light: {
          executor: 'constant-arrival-rate',
          exec: 'writeData',
          rate: 10,
          timeUnit: '1s',
          duration: '5m',
          preAllocatedVUs: 5,
          maxVUs: 20,
        },
      },
    };

    export function readData() {
      http.get('https://quickpizza.grafana.com/api/menu');
    }

    export function writeData() {
      http.post('https://quickpizza.grafana.com/api/orders', 
        JSON.stringify({ items: ['pizza'] }));
    }
    ```
  </Tab>
</Tabs>

## Executor Comparison

| Executor                | Control Type      | Use Case                       |
| ----------------------- | ----------------- | ------------------------------ |
| `constant-vus`          | VU count          | Steady-state load              |
| `ramping-vus`           | VU count          | Gradual load changes           |
| `constant-arrival-rate` | Iteration rate    | Fixed throughput               |
| `ramping-arrival-rate`  | Iteration rate    | Gradual throughput changes     |
| `shared-iterations`     | Total iterations  | Quick completion of fixed work |
| `per-vu-iterations`     | Per-VU iterations | Precise iteration count        |
| `externally-controlled` | External API      | Dynamic control                |

## Best Practices

1. **Use arrival rate for throughput testing** - When you care about requests/second, not VU count
2. **Set appropriate maxVUs** - For arrival rate executors, allocate enough VUs to maintain the rate
3. **Add graceful stop time** - Give long-running iterations time to complete
4. **Use scenario tags** - Tag scenarios for easier metric filtering
5. **Stagger scenario starts** - Avoid overwhelming the system at test start
6. **Name scenarios descriptively** - Use clear names like `api_load`, `browser_flow`, etc.

## Scenario Metrics

Filter metrics by scenario:

```javascript theme={null}
export let options = {
  scenarios: {
    api_test: {
      executor: 'constant-vus',
      vus: 10,
      duration: '1m',
    },
  },
  thresholds: {
    'http_req_duration{scenario:api_test}': ['p(95)<500'],
    'http_req_failed{scenario:api_test}': ['rate<0.01'],
    'iterations{scenario:api_test}': ['count>100'],
  },
};
```

## Next Steps

* Learn about [Tags and Groups](/writing-tests/tags-groups) for organizing test metrics
* Review [Test Options](/writing-tests/test-options) for global configuration
* Understand [Test Structure](/writing-tests/test-structure) fundamentals
