skip to content

In k6, why does adding --duration on the command line discard a whole scenarios map the script declared?

level: seniorimportance: must knowfreq 58%

answer

  1. four keys move together
  2. not a plain per-key merge
  3. lower layers are wiped, not blended
  4. vus is outside the group

basics

~10 s

Because duration, iterations, stages and scenarios form one execution group in k6: any of the four set in a higher layer clears all four from every lower layer before the new value is applied.

solid answer

~40 s

k6 merges most root options key by key, but `duration`, `iterations`, `stages` and `scenarios` are handled as a single execution group. When a higher layer sets any one of them, k6 first blanks all four in the accumulated lower layers, then applies the new value — so a `--duration 30s` flag removes the script's whole `scenarios` map rather than sitting alongside it. When the layer being overridden really did hold a `scenarios` map, k6 logs `"cli" level configuration overrode scenarios configuration entirely`; when it held only `stages` or `duration`, the replacement is silent. Clearing happens only across layers: two group keys in the same layer are both kept and then rejected, for example ``using `duration` and `stages` options simultaneously is not allowed``, which exits 104.

code

javascript · 11 lines
javascript
// script.js — three scenarios, none of which will run below
export const options = {
  scenarios: {
    smoke:  { executor: 'shared-iterations', vus: 1,  iterations: 10 },
    steady: { executor: 'constant-vus',      vus: 20, duration: '5m' },
    ramp:   { executor: 'ramping-vus', startVUs: 0,
              stages: [{ duration: '1m', target: 50 }] },
  },
};

export default function () {}

go deeper

for a junior

Remember the four names that travel together: duration, iterations, stages and scenarios. Setting any one of them higher up throws away all four from below, so a single flag can change the entire workload.

for a middle

Explain the mechanism: k6 blanks all four keys in the lower layers before applying the higher one, which is why you never get a mixed workload built from two different layers.

for a senior

Demonstrate that you check the resolved options rather than the script — read the override warning, know it is absent when the lower layer had no scenarios map, and inspect exec.test.options.scenarios.

for a principal

Decide what a team's pipeline may put on the command line at all, given that any execution-group key there silently replaces a declared workload and leaves no artifact behind.

## Options do not merge one key at a time Most k6 root options merge key by key: the highest layer that names `rps` sets `rps`, and everything else keeps whatever the lower layers said. Four keys break that rule, and they are exactly the four that describe the workload: - `duration` - `iterations` - `stages` - `scenarios` k6 treats them as one **execution group**. When a layer higher up the precedence chain sets **any one of the four**, k6 wipes **all four** from every lower layer first, and only then applies what the higher layer said. There is no blending: you never get the script's `stages` plus the CLI's `duration`. The reason is that these four keys are not independent settings — they are four alternative spellings of the same thing, the shape of the work k6 will schedule. `duration` plus `vus` is shorthand for a single `constant-vus` scenario; `iterations` plus `vus` is shorthand for a `shared-iterations` scenario; `stages` is shorthand for a `ramping-vus` scenario; and `scenarios` is the long form all three expand into. Since they are competing descriptions of one workload rather than four settings that compose, k6 resolves them as a unit: whichever layer speaks last describes the entire workload, and every earlier description is thrown away rather than partially reused. ## Why that turns one flag into a whole new workload A script exports a full `scenarios` map with three named scenarios. Someone runs it with `k6 run --duration 30s script.js`. Because `--duration` is in the group and sits at the top layer, k6 discards the entire map, keeps `duration: 30s`, and derives the default single-scenario shorthand from it. The three scenarios never start. The same happens in the other direction and between the middle layers: | Lower layer supplies | Higher layer supplies | What actually runs | |---|---|---| | config file `stages` | `K6_DURATION=15s` | one `constant-vus` scenario for 15s | | script `scenarios` map | `K6_ITERATIONS=25` | one `shared-iterations` scenario | | config file `stages` | CLI `--stage 44s:44` | one `ramping-vus` scenario from the CLI stages only | | script `duration` | CLI `--rps 50` | script duration survives; `rps` is not in the group | ## The warning is real but incomplete When the layer being overridden had an actual `scenarios` map, k6 logs a warning naming the layer that overrode it: - `"script" level configuration overrode scenarios configuration entirely` - `"env" level configuration overrode scenarios configuration entirely` - `"cli" level configuration overrode scenarios configuration entirely` **But the warning only fires when the lower layers had a `scenarios` map.** If the lower layer supplied only `stages` or only `duration`, the replacement is silent. So "no warning appeared" is not evidence that nothing was overridden. ## Two of the four in the same layer is an error, not a merge The clearing only happens *across* layers. If two group keys arrive in the **same** layer they are both kept, and validation then rejects the combination: 1. `duration` plus `stages` in one layer fails with ``using `duration` and `stages` options simultaneously is not allowed``. 2. `iterations` plus `stages` fails the same way, as do `duration` plus `scenarios` and `stages` plus `scenarios`. 3. Every one of those failures is a configuration error and exits **104**. That is why the error you would expect from `k6 run --duration 30s` against a script full of `stages` never appears — the flag removed the `stages` before validation ever saw them. ## What is *not* in the group `vus` is deliberately outside the execution group, so a `K6_VUS` variable can change the VU count while the script keeps owning `stages`. There is a separate trap, though: if `vus` is the **only** execution-shaped option set anywhere and a `scenarios` map exists, k6 logs `` `vus=8` overrides scenarios configuration `` and replaces the map with a `shared-iterations` scenario of 8 VUs and 8 iterations. Same visible outcome, different mechanism — that one happens when k6 derives scenarios from shorthand options, not during the layer merge. ## How to check a run you did not launch yourself - Read the warning lines at the top of the k6 output for `overrode scenarios configuration entirely`. - Print `exec.test.options.scenarios` from inside the test to see the map k6 actually resolved. - Remember that all four group keys can arrive from four different places, so scan the config file, the script, the environment and the command line before concluding the script is wrong.

  • Does k6 always warn when a higher layer replaces the workload?
    No. The warning fires only when the accumulated lower layers actually held a `scenarios` map. If they held only `stages` or `duration`, the higher layer clears them silently — a config file's `stages` replaced by a CLI `--stage` produces no warning at all. Absence of the warning is not evidence that nothing was overridden.
  • Why does k6 reject duration and stages together, if higher layers clear them anyway?
    The clearing is only across layers. Two group keys arriving in the same layer are both preserved so that validation can report the conflict, which it does with ``using `duration` and `stages` options simultaneously is not allowed`` and exit code 104. Across layers you never see that error, because the higher key removed the lower one before validation ran.
  • Is --vus part of the execution group in k6?
    No — `vus` merges independently, so `K6_VUS` can change the VU count while the script keeps owning `stages`. But when `vus` is the only execution-shaped option set and a `scenarios` map exists, k6 still discards the map while deriving scenarios, logging `` `vus=N` overrides scenarios configuration `` and running a `shared-iterations` scenario with N VUs and N iterations.

Setting any of the four is like handing the kitchen a new recipe card rather than editing one line of the old one: k6 throws the previous card away before reading the new one, so nothing from the old recipe survives.

saying these in an interview costs you the question

  • Thinks a higher layer replaces only the single key it names
  • Expects a CLI duration to merge with the script's stages
  • Believes k6 always warns when a workload is replaced
  • Assumes vus is cleared along with duration and stages
  • Says duration and stages together in one layer is legal
  • Reads a missing warning as proof nothing was overridden