In a k6 ramping-vus scenario, what do the duration and target of one stages entry mean?
answer
- the number is where you end up
- each stage starts where the last one stopped
- durations are consecutive, not offsets
- repeat a target to keep it flat
basics
~20 sIn k6's ramping-vus executor, a stages entry's target is the VU count reached at the end of the stage, and duration is how long the linear move from the current count takes. Repeating the previous target holds that level.
solid answer
~40 sEach element of a `ramping-vus` `stages` array is a `{ duration, target }` pair, and both fields are required. `target` is the VU count k6 should have reached **at the end** of the stage, not a level held throughout it: k6 interpolates the count linearly from whatever is running when the stage starts — `startVUs` for the first stage, the previous stage's target afterwards. `duration` is that stage's own length, and because stages run consecutively, their durations sum to the scenario's scheduled length. Two idioms follow from this: a stage whose `target` repeats the previous one holds the count flat, and a stage with `duration: '0s'` jumps to its target instantly. k6 rejects a stage that is missing either field, and rejects an empty `stages` array outright.
code
javascript · 19 linesimport http from 'k6/http';
export const options = {
scenarios: {
ramp: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '2m', target: 200 },
{ duration: '5m', target: 200 },
{ duration: '2m', target: 0 },
],
},
},
};
export default function () {
http.get('https://quickpizza.grafana.com/');
}go deeper
Remember the two fields and their meaning: duration is how long the stage lasts, target is how many VUs are running when it finishes. Both are required in every entry.
Explain the interpolation: the ramp starts from the count already running, so a stage that repeats the previous target holds flat, and the durations add up to the scenario's scheduled length.
Show you can read a profile off an array and back: name the VU count at any instant, and know that a zero-duration stage is the supported way to step the count instantly.
Weigh how much profile belongs in one stages array. A long array hides a whole shape in one anonymous scenario; splitting it into named scenarios entries keeps the executor and its keys visible in review.
## One entry, two fields In a k6 `ramping-vus` scenario, `stages` is a required array and each element is an object with exactly two fields: - **`duration`** — how long this stage lasts, as a k6 duration string such as `'30s'`, `'2m'` or `'1h30m'`. - **`target`** — the number of VUs that should be running **when the stage ends**. Both fields are mandatory. k6 rejects an entry missing either one with *"stage N doesn't have a duration"* or *"stage N doesn't have a target"* (stages are numbered from 1 in the message), and rejects a negative value for either. An empty array is rejected too: *"at least one stage has to be specified"*. ## `target` is an endpoint, not a level to sit at This is where most misreadings start. A stage does not *hold* its target for its duration — it **arrives** at the target by the end of the duration. k6's own field comment says it plainly: if a target is set, the VU count is **linearly interpolated** toward it. The interpolation starts from whatever count is running when the stage begins, which is `startVUs` for the first stage and the previous stage's target for every one after it. Nothing in the entry says where the ramp starts; that is always inherited. Because the durations are consecutive rather than absolute offsets from the start of the run, the sum of all the stage durations is the scenario's scheduled length. Three stages of `2m`, `5m` and `2m` describe a nine-minute scenario, not a five-minute one. ## Reading a three-stage profile Take a scenario with `startVUs: 0` and these stages: ``` { duration: '2m', target: 200 } { duration: '5m', target: 200 } { duration: '2m', target: 0 } ``` | stage | entry | VUs at its start | VUs at its end | what happens across it | |---|---|---|---|---| | 1 | `{ duration: '2m', target: 200 }` | 0, from `startVUs` | 200 | count climbs linearly, so t=1m is about 100 VUs | | 2 | `{ duration: '5m', target: 200 }` | 200 | 200 | the target repeats, so the count sits at 200 | | 3 | `{ duration: '2m', target: 0 }` | 200 | 0 | count falls linearly back to nothing | Nine minutes of schedule, a peak of 200 VUs, and only the middle stage is flat. ## Holds, instant jumps and zero 1. **A hold is a repeated target.** There is no separate "hold" key. When a stage's `target` equals the count already running, k6 computes a VU difference of zero and emits no intermediate steps, so the count simply stays put for that stage's `duration`. 2. **A jump is a zero-duration stage.** `{ duration: '0s', target: 200 }` is legal and moves the count to 200 instantaneously. k6 allows this deliberately — the one-second minimum it enforces on the `constant-vus` `duration` explicitly does not apply to stage durations. 3. **Zero is a valid target and a valid start.** `startVUs: 0` and a final `target: 0` are both fine. The only rule is that `startVUs` or at least one `target` must exceed 0, otherwise there is no work to do and k6 reports *"either startVUs or one of the stages' target values must be greater than 0"*. Targets may also move up and down repeatedly; k6 recomputes the slope for each stage independently, so a saw-toothed `stages` array is a legal, if unusual, description. ## Where the count is when the scenario opens `startVUs` defaults to `1`, which surprises people who write only stages: without an explicit `startVUs`, the first stage ramps from one VU rather than from zero. Set `startVUs: 0` when you want the first stage to build the whole count from nothing. ## What the entries do not control A stage entry has exactly two fields and no other knobs: - It **cannot change the function being run**. Which exported function the VUs call is the scenario's `exec` key, set once for the whole scenario, not per stage. - It **carries no wind-down of its own**. When a stage's target is lower than the count already running, `gracefulRampDown` — a sibling key of `stages` on the same executor, defaulting to `30s` — governs how long the VUs being dropped may keep finishing their current iteration. - It **cannot bend the line**. There is no easing or progression field in k6 v2: every stage is a straight line between two counts, and a curve has to be approximated by several short stages. - It **cannot pause**. A stage with `target` equal to 0 in the middle of an array drives the count to zero and then the next stage builds it back up; that is a trough, not a suspended scenario.
- How long does a k6 ramping-vus scenario with stages of 2m, 5m and 2m run?Nine minutes of schedule. Stage durations are consecutive lengths, not absolute offsets from the scenario's start, so k6 adds them up. Elapsed wall-clock time can exceed that slightly, because VUs finishing their last iterations inside a graceful window keep the scenario alive a little longer than its stages.
- What does a k6 ramping-vus scenario do if you set stages but never set startVUs?It starts from one VU. `startVUs` defaults to `1`, so the first stage interpolates from 1 to its target rather than from 0. Write `startVUs: 0` explicitly when you want the first stage to build the entire count from nothing.
- Can a k6 ramping-vus stage ramp non-linearly?No. In k6 v2 a stage is always a straight line between the count running at its start and its `target`; the entry has no curve or easing field. Approximate a curve by chopping it into several short stages with different targets.
saying these in an interview costs you the question
- Reads target as a level held for the stage's duration
- Treats each stage duration as an offset from the run's start
- Thinks a stage ramps from zero rather than the current count
- Believes a hold needs a separate key instead of a repeated target
- Assumes startVUs defaults to 0 when it is left out