Skip to main content
The ramping-arrival-rate executor starts iterations at a variable rate that changes over defined stages. This combines the throughput-focused approach of arrival rate executors with the flexibility of ramping patterns.

How It Works

With ramping arrival rate:
  1. Iteration rate starts at startRate per timeUnit
  2. Rate increases/decreases linearly to each stage’s target
  3. k6 automatically allocates VUs to maintain the target rate
  4. VUs scale up/down dynamically as the rate changes
  5. If maxVUs is insufficient, iterations are dropped
Rate ^
 (iters/sec)
 100 |          ╱‾‾‾‾‾╲
  75 |        ╱        ╲
  50 |      ╱            ╲___
  25 |    ╱                  ╲
   0 |╺━━╯                    ╲___
     +--------------------------------> time
       2m    3m    2m    1m    2m
       (stages)

VUs dynamically adjust to maintain rate

Configuration

executor
string
required
Must be ramping-arrival-rate
startRate
integer
default:"0"
Number of iterations to start per timeUnit. Can be 0.
timeUnit
duration
default:"1s"
Period over which startRate and stage targets are calculated.
stages
array
required
Array of stage objects defining the iteration rate pattern.
stages[].duration
duration
required
Duration of this stage.
stages[].target
integer
required
Target iteration rate at the end of this stage (per timeUnit).
preAllocatedVUs
integer
required
Number of VUs to pre-allocate before test start.
maxVUs
integer
default:"preAllocatedVUs"
Maximum number of VUs allowed. Cannot be less than preAllocatedVUs.

Example

Progressive Load Test

import http from 'k6/http';
import { sleep } from 'k6';

export const options = {
  scenarios: {
    progressive_load: {
      executor: 'ramping-arrival-rate',
      startRate: 0,
      timeUnit: '1s',
      preAllocatedVUs: 50,
      maxVUs: 200,
      stages: [
        { duration: '2m', target: 10 },   // Ramp to 10 iters/s
        { duration: '5m', target: 10 },   // Hold at 10 iters/s
        { duration: '2m', target: 50 },   // Ramp to 50 iters/s
        { duration: '5m', target: 50 },   // Hold at 50 iters/s
        { duration: '2m', target: 100 },  // Ramp to 100 iters/s
        { duration: '5m', target: 100 },  // Hold at 100 iters/s
        { duration: '2m', target: 0 },    // Ramp down
      ],
    },
  },
};

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

Breakpoint Test - Find Rate Limit

import http from 'k6/http';

export const options = {
  scenarios: {
    find_breakpoint: {
      executor: 'ramping-arrival-rate',
      startRate: 0,
      timeUnit: '1s',
      preAllocatedVUs: 100,
      maxVUs: 1000,
      stages: [
        { duration: '5m', target: 100 },
        { duration: '5m', target: 200 },
        { duration: '5m', target: 400 },
        { duration: '5m', target: 800 },
        { duration: '5m', target: 1600 },
      ],
    },
  },
  thresholds: {
    http_req_failed: ['rate<0.05'],
    http_req_duration: ['p(95)<2000'],
  },
};

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

Traffic Pattern Simulation

import http from 'k6/http';

export const options = {
  scenarios: {
    daily_pattern: {
      executor: 'ramping-arrival-rate',
      startRate: 10,        // Night traffic: 10 RPS
      timeUnit: '1s',
      preAllocatedVUs: 20,
      maxVUs: 300,
      stages: [
        // Morning ramp-up
        { duration: '2m', target: 50 },   // 6-8 AM
        { duration: '3m', target: 100 },  // 8-11 AM
        
        // Lunch spike
        { duration: '1m', target: 150 },  // 11 AM-12 PM
        { duration: '2m', target: 150 },  // 12-2 PM
        { duration: '1m', target: 100 },  // 2-3 PM
        
        // Afternoon
        { duration: '3m', target: 80 },   // 3-6 PM
        
        // Evening spike
        { duration: '1m', target: 120 },  // 6-7 PM
        { duration: '2m', target: 120 },  // 7-9 PM
        
        // Night ramp-down
        { duration: '2m', target: 50 },   // 9-11 PM
        { duration: '2m', target: 10 },   // 11 PM-1 AM
      ],
    },
  },
};

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

When to Use

Use the ramping arrival rate executor when:
  • You need to test varying throughput over time
  • You want to find the maximum sustainable request rate
  • You’re simulating realistic traffic patterns with peaks and valleys
  • You need to test auto-scaling response to changing load
  • Iteration duration varies and you want consistent throughput
  • You’re testing rate limiting under varying load
  • You want to observe system behavior as load increases gradually

Behavior Details

Linear Rate Ramping

Iteration rate changes linearly between stage targets:
stages: [
  { duration: '60s', target: 60 },
]
// At t=0s:  0 iters/s
// At t=10s: 10 iters/s
// At t=30s: 30 iters/s
// At t=60s: 60 iters/s

Dynamic VU Scaling

VUs automatically scale to maintain the target rate:
// If iteration duration is 200ms:
// Rate: 10 iters/s needs ~2 VUs
// Rate: 50 iters/s needs ~10 VUs
// Rate: 100 iters/s needs ~20 VUs

Rate Calculation

The iteration rate is spread evenly over the time period:
// With timeUnit: '1s' and target: 100
// = 100 iterations every 1 second
// = 1 iteration every 10ms

// With timeUnit: '1m' and target: 600
// = 600 iterations every 60 seconds  
// = 10 iterations per second

Stage Transitions

Transitions between stages are smooth and continuous:
stages: [
  { duration: '1m', target: 50 },   // End at 50 iters/s
  { duration: '2m', target: 100 },  // Start at 50, ramp to 100
]
// No gap between stages - rate smoothly increases from 50 to 100

Common Patterns

Gradual Capacity Test

export const options = {
  scenarios: {
    capacity: {
      executor: 'ramping-arrival-rate',
      startRate: 0,
      timeUnit: '1s',
      preAllocatedVUs: 50,
      maxVUs: 500,
      stages: [
        { duration: '10m', target: 50 },
        { duration: '10m', target: 100 },
        { duration: '10m', target: 150 },
        { duration: '10m', target: 200 },
        { duration: '10m', target: 250 },
      ],
      gracefulStop: '2m',
    },
  },
  thresholds: {
    http_req_duration: ['p(99)<3000'],
    dropped_iterations: ['rate<0.01'],
  },
};

Spike and Recovery

export const options = {
  scenarios: {
    spike_test: {
      executor: 'ramping-arrival-rate',
      startRate: 20,
      timeUnit: '1s',
      preAllocatedVUs: 50,
      maxVUs: 500,
      stages: [
        { duration: '2m', target: 20 },    // Baseline
        { duration: '30s', target: 200 },  // Rapid spike
        { duration: '3m', target: 200 },   // Sustain spike
        { duration: '30s', target: 20 },   // Rapid drop
        { duration: '2m', target: 20 },    // Observe recovery
      ],
    },
  },
};

Stepped Increases

export const options = {
  scenarios: {
    stepped: {
      executor: 'ramping-arrival-rate',
      startRate: 10,
      timeUnit: '1s',
      preAllocatedVUs: 20,
      maxVUs: 200,
      stages: [
        { duration: '5m', target: 10 },
        { duration: '0s', target: 25 },   // Instant jump
        { duration: '5m', target: 25 },
        { duration: '0s', target: 50 },   // Instant jump
        { duration: '5m', target: 50 },
        { duration: '0s', target: 100 },  // Instant jump
        { duration: '5m', target: 100 },
      ],
    },
  },
};

VU Sizing

Calculate VU requirements for peak rate:
Required VUs ≈ (peak_rate × avg_iteration_duration) / timeUnit

Example:
- Peak rate: 200 iterations/second
- Average iteration: 300ms
- Required VUs ≈ 200 × 0.3 = 60 VUs

Recommended:
- preAllocatedVUs: 60 (for peak)
- maxVUs: 120 (2x safety margin)

Metrics

Key metrics to monitor:
  • iterations - Total completed iterations
  • iteration_duration - How long iterations take
  • dropped_iterations - Iterations dropped (insufficient VUs)
  • vus - Current active VUs
  • vus_max - Current allocated VUs (≤ maxVUs)
The current iteration rate can be derived from:
rate = iterations_per_second

Advanced Configuration

Multiple Traffic Types

export const options = {
  scenarios: {
    read_traffic: {
      executor: 'ramping-arrival-rate',
      startRate: 50,
      timeUnit: '1s',
      stages: [
        { duration: '5m', target: 100 },
        { duration: '10m', target: 100 },
        { duration: '5m', target: 50 },
      ],
      preAllocatedVUs: 30,
      maxVUs: 100,
      exec: 'readTest',
      tags: { type: 'read' },
    },
    write_traffic: {
      executor: 'ramping-arrival-rate',
      startRate: 10,
      timeUnit: '1s',
      stages: [
        { duration: '5m', target: 20 },
        { duration: '10m', target: 20 },
        { duration: '5m', target: 10 },
      ],
      preAllocatedVUs: 10,
      maxVUs: 50,
      exec: 'writeTest',
      tags: { type: 'write' },
    },
  },
};

export function readTest() {
  http.get('https://test.k6.io/api/data');
}

export function writeTest() {
  http.post('https://test.k6.io/api/data', { data: 'value' });
}

Best Practices

  1. Size maxVUs generously: Allow 2-3x expected VUs for rate variance
  2. Start from baseline: Use realistic startRate from production metrics
  3. Gradual ramp-up: Give system time to warm up and scale
  4. Monitor dropped_iterations: Set thresholds to detect insufficient VUs
  5. Test auto-scaling: Design stages to test scaling triggers
  6. Use realistic patterns: Model actual production traffic patterns
  7. Consider iteration variance: Account for varying iteration durations
  8. Set appropriate timeUnit: Match your SLA/monitoring granularity

Comparison with Other Executors

FeatureRamping Arrival RateConstant Arrival RateRamping VUs
Rate patternVariable over stagesFixedN/A (not rate-based)
VU countDynamic (auto-scaled)Dynamic (auto-scaled)Fixed per stage
ComplexityHighMediumMedium
ThroughputVaries by stageConstantVariable (depends on VUs)
Best forComplex traffic patternsSteady throughputUser simulation

Troubleshooting

High Dropped Iterations

// Problem: dropped_iterations increasing
// Solution: Increase maxVUs
{
  maxVUs: 500,  // Increase from 200
}

VU Churn (Frequent Allocation)

// Problem: VUs constantly being allocated/deallocated
// Solution: Increase preAllocatedVUs to peak needs
{
  preAllocatedVUs: 100,  // Increase from 50
}

Rate Not Achieved

Check:
  1. maxVUs sufficient for iteration duration × rate
  2. Backend can handle the load (not throttling)
  3. Network bandwidth adequate
  4. dropped_iterations metric for evidence

See Also

Build docs developers (and LLMs) love