> ## 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.

# Per VU Iterations Executor

> Each VU executes a fixed number of iterations

The `per-vu-iterations` executor ensures that each VU runs an exact number of iterations. Unlike shared iterations where VUs compete for iterations, here every VU completes its own fixed quota of iterations.

## How It Works

With per-VU iterations:

1. Each VU is assigned a fixed number of iterations
2. VUs run independently without competing
3. Total iterations = `vus × iterations`
4. Each VU completes all its iterations or runs until `maxDuration`
5. All VUs complete the same number of iterations (if within maxDuration)

```
VU 1: [iter 1][iter 2][iter 3]  (3 iterations)
VU 2: [iter 1][iter 2][iter 3]  (3 iterations)  
VU 3: [iter 1][iter 2][iter 3]  (3 iterations)

Total: 9 iterations (3 VUs × 3 iterations each)
```

## Configuration

<ParamField path="executor" type="string" required>
  Must be `per-vu-iterations`
</ParamField>

<ParamField path="vus" type="integer" default="1">
  Number of VUs to run concurrently. Must be greater than 0.
</ParamField>

<ParamField path="iterations" type="integer" default="1">
  Number of iterations each VU executes. Must be greater than 0.
</ParamField>

<ParamField path="maxDuration" type="duration" default="10m">
  Maximum duration for the executor. If a VU's iterations don't complete within this time, remaining iterations are dropped.
</ParamField>

## Example

### Basic Configuration

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

export const options = {
  scenarios: {
    per_vu_scenario: {
      executor: 'per-vu-iterations',
      vus: 10,
      iterations: 20,
      maxDuration: '1m',
    },
  },
};

export default function () {
  http.get('https://test.k6.io');
  sleep(1);
}
```

This runs 10 VUs, each executing 20 iterations, for a total of 200 iterations.

### Per-User Session Simulation

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

export const options = {
  scenarios: {
    user_sessions: {
      executor: 'per-vu-iterations',
      vus: 50,
      iterations: 10, // Each user completes 10 sessions
      maxDuration: '5m',
    },
  },
};

export default function () {
  // Login
  const loginRes = http.post('https://test.k6.io/login', {
    username: `user_${__VU}`,
    password: 'password',
  });
  
  check(loginRes, { 'login successful': (r) => r.status === 200 });
  sleep(1);
  
  // Browse
  http.get('https://test.k6.io/products');
  sleep(2);
  
  // Logout
  http.post('https://test.k6.io/logout');
  sleep(1);
}
```

## When to Use

Use the per-VU iterations executor when:

* You want consistent work per VU (e.g., each user completes 10 sessions)
* You need predictable per-VU behavior for testing
* You're simulating realistic user behavior where each user does a set amount of work
* You want the total iterations to scale linearly with VUs
* You need to test with isolated per-VU data or state

## Behavior Details

### Total Iterations

The total number of iterations is the product of VUs and iterations per VU:

```javascript theme={null}
export const options = {
  scenarios: {
    example: {
      executor: 'per-vu-iterations',
      vus: 10,
      iterations: 5,
      // Total iterations: 10 × 5 = 50
    },
  },
};
```

### VU Isolation

Each VU maintains its own iteration counter and executes independently:

```javascript theme={null}
export default function () {
  console.log(`VU ${__VU}, iteration ${__ITER}`);
  // VU 1: iterations 0, 1, 2, 3, 4...
  // VU 2: iterations 0, 1, 2, 3, 4...
  // VU 3: iterations 0, 1, 2, 3, 4...
}
```

### Maximum Duration

If a VU cannot complete all iterations within `maxDuration`, remaining iterations are dropped:

```javascript theme={null}
export const options = {
  scenarios: {
    example: {
      executor: 'per-vu-iterations',
      vus: 5,
      iterations: 100,
      maxDuration: '10s', // May not complete all 100 per VU
    },
  },
};
```

Dropped iterations are tracked per VU in the `dropped_iterations` metric.

### Scaling Behavior

<Warning>
  When using execution segments for distributed testing, only VUs are scaled, NOT iterations per VU. This maintains linear scaling.
</Warning>

Example with 50% execution segment:

```javascript theme={null}
// Original config
{
  vus: 10,
  iterations: 20,
  // Total: 200 iterations
}

// With 50% segment (0:0.5)
// Scaled VUs: 5
// Iterations per VU: 20 (unchanged)
// Total: 100 iterations (50% of original)
```

## Metrics

The executor emits these metrics:

* `iterations` - Total completed iterations across all VUs
* `iteration_duration` - Time to complete each iteration
* `dropped_iterations` - Iterations that didn't complete within `maxDuration` (tracked per VU)
* `vus` - Number of active VUs
* `vus_max` - Maximum number of VUs

## Common Patterns

### User Journey Testing

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

export const options = {
  scenarios: {
    user_journey: {
      executor: 'per-vu-iterations',
      vus: 20,
      iterations: 5, // Each user completes journey 5 times
    },
  },
};

export default function () {
  // Complete user journey
  http.get('https://test.k6.io');
  sleep(1);
  
  http.get('https://test.k6.io/products');
  sleep(2);
  
  http.post('https://test.k6.io/cart/add', { productId: 123 });
  sleep(1);
  
  http.post('https://test.k6.io/checkout');
  sleep(1);
}
```

### Per-VU Data Processing

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

const users = new SharedArray('users', function () {
  return JSON.parse(open('./users.json'));
});

export const options = {
  scenarios: {
    user_requests: {
      executor: 'per-vu-iterations',
      vus: users.length,
      iterations: 10, // Each user makes 10 requests
    },
  },
};

export default function () {
  const user = users[__VU - 1]; // Each VU gets one user
  http.post('https://test.k6.io/api', JSON.stringify({
    userId: user.id,
    iteration: __ITER,
  }));
}
```

### Ramping Users with Fixed Work

Combine with other executors for complex scenarios:

```javascript theme={null}
export const options = {
  scenarios: {
    warmup: {
      executor: 'per-vu-iterations',
      vus: 1,
      iterations: 10,
      startTime: '0s',
    },
    main_load: {
      executor: 'per-vu-iterations',
      vus: 50,
      iterations: 20,
      startTime: '30s', // Start after warmup
    },
  },
};
```

## Comparison with Shared Iterations

| Feature          | Per VU Iterations        | Shared Iterations            |
| ---------------- | ------------------------ | ---------------------------- |
| Total iterations | `vus × iterations`       | Fixed total                  |
| Distribution     | Even (each VU does same) | Dynamic (faster VUs do more) |
| VU workload      | Equal                    | Unequal                      |
| Predictability   | High per-VU              | High total                   |
| Scaling          | Linear with VUs          | Independent of VUs           |
| Use case         | Consistent per-user load | Fixed total work             |

## Best Practices

1. **Set realistic maxDuration**: Ensure each VU has enough time to complete all iterations
2. **Use for user simulation**: Great for simulating N users each doing M actions
3. **Monitor per-VU metrics**: Use `__VU` and `__ITER` to track per-VU behavior
4. **Consider VU reuse**: VUs are reused across iterations, so handle state appropriately
5. **Plan for scaling**: Remember only VUs scale in distributed testing, not iterations

## See Also

* [Shared Iterations](/executors/shared-iterations) - Fixed total iterations shared among VUs
* [Constant VUs](/executors/constant-vus) - Time-based execution with fixed VUs
