Skip to content

k6 Stages Ramp-Up Not Reaching Target VUs Fix

DodaTech Updated 2026-06-24 3 min read

In this tutorial, you'll learn about k6 stages ramp. We cover key concepts, practical examples, and best practices.

Your k6 test reaches fewer virtual users than the stage target — vus: 50 shows min=0 max=22 at peak. The stage duration is too short for the ramp-up rate, the system under test throttles connections, or the load generator runs out of resources.

The Problem

import http from 'k6/http';

export const options = {
  stages: [
    { duration: '5s', target: 100 },
    { duration: '10s', target: 100 },
    { duration: '5s', target: 0 },
  ],
};

export default function () {
  http.get('https://api.example.com');
}
     vus.......................: 22    min=0  max=22
     vus_max...................: 22    min=22 max=22

The ramp-up stage is 5 seconds trying to reach 100 VUs — that is 20 VUs/second. The system may not accept connections that fast, or k6's executor cannot ramp up that quickly on the current machine.

Step-by-Step Fix

1. Increase stage duration for gradual ramp-up

export const options = {
  stages: [
    { duration: '30s', target: 100 },  // ~3.3 VUs/second
    { duration: '1m', target: 100 },
    { duration: '30s', target: 0 },
  ],
};

2. Add a warm-up stage

export const options = {
  stages: [
    { duration: '10s', target: 10 },    // Warm up
    { duration: '30s', target: 50 },    // Ramp to moderate load
    { duration: '1m', target: 100 },    // Full load
    { duration: '30s', target: 0 },     // Ramp down
  ],
};

3. Use the ramping-vus executor explicitly

export const options = {
  scenarios: {
    ramp_test: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '30s', target: 50 },
        { duration: '1m', target: 100 },
        { duration: '30s', target: 0 },
      ],
      gracefulRampDown: '30s',
    },
  },
};

4. Check system resources on the load generator

# Check available file descriptors
ulimit -n

# Check CPU and memory
htop

# Check network connections
ss -s

5. Verify with a minimal script

import { sleep } from 'k6';

export const options = {
  stages: [
    { duration: '10s', target: 50 },
    { duration: '10s', target: 50 },
    { duration: '10s', target: 0 },
  ],
};

export default function () {
  sleep(1);  // No HTTP calls — just test VU scaling
}

Expected output:

     vus.......................: 50    min=0  max=50
     vus_max...................: 50    min=50 max=50

If VUs reach the target with no HTTP calls, the bottleneck is on the target server, not k6.

Prevention Tips

  • Keep ramp-up rate below 10 VUs/second for realistic load patterns
  • Use gracefulRampDown to prevent connection spikes during ramp-down
  • Monitor load generator CPU/memory during high-VU tests
  • Test VU scaling with a minimal script first
  • Use scenarios with ramping-vus executor for precise control

Common Mistakes with stages

  1. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
  2. Non-exhaustive pattern matches that compile with warnings then crash at runtime
  3. Misunderstanding that String is [Char] with poor performance for large text operations

These mistakes appear frequently in real-world K6 code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### What's the difference between stages and scenarios?

stages is a simplified API for the ramping-vus executor. scenarios provides full control over multiple executors (ramping-vus, constant-vus, per-vu-iterations, externally-controlled). Use stages for simple tests, scenarios for complex ones.

Why does my stage not reach the target VU count?

Three common causes: (1) stage duration is too short for the ramp-up rate, (2) the load generator runs out of file descriptors (ulimit), or (3) the system under test throttles incoming connections. Increase duration, check ulimit, and verify with a no-op script.

Can I use stages with the browser module?

Yes. The k6 browser module supports stages. Browser tests use more resources per VU (each VU opens a browser context), so reduce target VUs by 10-20x compared to HTTP-only tests.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro