skip to content

For a team's k6 suite, how would you decide which of the five option layers each setting lives in?

level: principalimportance: should knowfreq 40%

answer

  1. some layers cannot express everything
  2. the workload group is all-or-nothing
  3. CI needs a layer it can inject
  4. scenarios has no flag form

basics

~20 s

Put the workload in the script's scenarios, because K6_ variables and CLI flags cannot supply one and can only wipe it. Reserve the top two layers for per-run switches such as K6_OUT that no scenario key depends on.

solid answer

~40 s

Three k6 facts settle most of it. `scenarios` has no `K6_*` variable and no CLI flag, so only the script and the `--config` file can express it. `duration`, `iterations`, `stages` and `scenarios` form one execution group that a higher layer clears wholesale, so the top two layers can destroy a workload but never rebuild it. And the default `config.json` is read on every run from the OS config directory, whether or not anyone names it. So the workload and `thresholds` belong in the script; environment-shaped keys such as `K6_OUT`, `K6_BLOCK_HOSTNAMES` and `K6_INSECURE_SKIP_TLS_VERIFY` belong in the pipeline; and a suite built on `scenarios` must ban `--duration`, `--iterations`, `--stage` and `--vus` along with their `K6_*` forms, since any of them collapses the map.

code

bash · 8 lines
bash
# Allowed at the top two layers: nothing in the execution group.
K6_OUT=json=results.json \
K6_BLOCK_HOSTNAMES="*.doubleclick.net" \
  k6 run -c ./k6.config.json ./suites/checkout.js

# Banned on a scenarios-based suite - each one collapses the map:
#   --duration/-d  --iterations/-i  --stage/-s  --vus/-u
#   K6_DURATION    K6_ITERATIONS    K6_STAGES   K6_VUS

go deeper

for a junior

Keep the workload in the script's options object and pass nothing workload-shaped on the command line. If you need a quick short run, copy the script rather than adding --duration to a scenarios-based suite.

for a middle

Explain which layers can express which options: scenarios only from the script or config file, everything workload-shaped clearable from above, and K6_ names mapping one-to-one onto option keys.

for a senior

Show how you would prove what a pipeline ran — the override warning, exec.test.options.scenarios, and an explicit -c file instead of the ambient per-machine config.json.

for a principal

Own the policy: which layer each class of setting lives in, what the pipeline is forbidden to pass, and how the suite fails loudly when a higher layer rewrites the declared workload.

## Let k6's own asymmetries make the decision The layer policy for a team's k6 suite is not a matter of taste; three mechanical facts about k6 v2 narrow it almost completely. 1. **`scenarios` has no environment variable and no CLI flag.** It can only come from the script's exported `options` or from the JSON file behind `--config`. The two highest layers cannot express it. 2. **`duration`, `iterations`, `stages` and `scenarios` are one execution group.** Any of the four set in a higher layer clears all four below it. There is no partial override of a workload. 3. **The default `config.json` is read on every run** from the OS configuration directory, whether or not anyone names it — so it is a layer that exists on developer machines without appearing in any command. Put together: the top two layers can wipe a workload but never describe one, and the bottom settable layer is machine-local and invisible. That points every workload description at layer 3, the script. ## Where each kind of setting belongs | Kind of setting | Layers that can express it | Recommended home | |---|---|---| | Workload — `scenarios` | script, config file | script `options` | | Workload shorthand — `duration`, `iterations`, `stages` | all five | script `options`, or nowhere | | Threshold expressions — `thresholds` | script, config file, `K6_THRESHOLDS` | script `options` | | Host and TLS — `blockHostnames`, `insecureSkipTLSVerify`, `hosts` | script, file, `K6_*`, most have flags | `K6_*` in the pipeline | | Result routing — `out` | file, `K6_OUT`, `--out` | pipeline, per run | | One-off debugging — `httpDebug` | script, file, `K6_HTTP_DEBUG`, `--http-debug` | interactive shell only | ## What the top two layers are genuinely good for - **`K6_*` variables** are the layer a build system can set without editing a file: `K6_OUT`, `K6_BLOCK_HOSTNAMES`, `K6_INSECURE_SKIP_TLS_VERIFY`, `K6_NO_CONNECTION_REUSE`. They are keyed one-to-one off the option name, so they are easy to generate. - **CLI flags** are the highest layer and leave no trace in the repository. Reserve them for things nobody needs to reproduce from the checkout: `--http-debug`, `-c` pointing at an alternative file, an ad-hoc `--out`. - **Neither** should carry the workload, because neither can put it back. The `--config` flag is the interesting exception at the top: it is a CLI flag, but all it does is choose which layer-2 file participates. Naming it explicitly is therefore the one command-line habit that makes the chain *more* legible rather than less, because it replaces an ambient per-machine file with a path anyone can open. ## The one option that needs a rule of its own `thresholds` has no CLI flag, but it does have a `K6_THRESHOLDS` variable and a config-file key, so unlike `scenarios` it can be moved up out of the script by accident: - In the script it sits beside the `scenarios` it judges, in the same reviewed file. - Set from the environment or a file, it can be changed for one pipeline without the script changing at all, and nothing in the script hints that a different rule was in force. - Unlike the execution group, a higher layer's `thresholds` replaces the map wholesale rather than merging per metric, so a partial override silently drops every rule it does not restate. ## The rule that follows for the workload If the suite declares `scenarios`, the policy has to ban more than `--scenarios` (which does not exist anyway). It must ban every member of the execution group at the top two layers: 1. `--duration` / `-d`, `--iterations` / `-i`, `--stage` / `-s`, and `--vus` / `-u`. 2. `K6_DURATION`, `K6_ITERATIONS`, `K6_STAGES`, `K6_VUS`. 3. Any wrapper script or CI template that adds one of them "for convenience". `--vus` deserves its own line: it is not in the execution group, so it is not cleared by the merge, but when it is the only execution-shaped option present it still replaces a `scenarios` map with a `shared-iterations` scenario of N VUs and N iterations, logging `` `vus=N` overrides scenarios configuration ``. ## What to standardise beyond the ban - **Pin the file layer.** Use an explicit `-c ./k6.config.json` in the repository rather than relying on the per-machine default `config.json`, so nobody's leftover file joins the merge. - **Name the layer in review.** A pull request that moves a threshold from the script into a `K6_*` variable moves it above the reviewed file; treat that as a change to the run, not a refactor. - **Watch for the warning.** `"cli" level configuration overrode scenarios configuration entirely` in a pipeline log means a flag replaced the declared workload — but the warning is absent when the lower layer had only `stages` or `duration`, so a silent replacement is still possible. - **Assert the resolved shape.** `exec.test.options.scenarios` inside the test shows what k6 actually built, which is the only layer-proof way to know what ran.

  • How would you detect that a k6 pipeline overrode a declared workload?
    Grep the run log for `overrode scenarios configuration entirely`, which names the offending layer as `script`, `env` or `cli`. That warning only fires when the lower layers held a real `scenarios` map, so back it up by reading `exec.test.options.scenarios` inside the test and failing the run when the resolved map is not the one the script declared.
  • Should a team rely on k6's default config.json path or an explicit -c file?
    An explicit `-c ./k6.config.json` from the repository. The default path is per machine, is read on every run without appearing on any command line, and on a workstation may already exist because `k6 cloud login` wrote a token into it. Naming the file makes layer 2 reviewable rather than ambient.
  • Which k6 settings are genuinely suited to the K6_ layer?
    Keys that describe the machine or target rather than the test: `K6_OUT` for result routing, `K6_BLOCK_HOSTNAMES`, `K6_INSECURE_SKIP_TLS_VERIFY`, `K6_NO_CONNECTION_REUSE`, `K6_HOSTS`. They are one-to-one with option names, so a pipeline can generate them, and none of them belongs to the execution group.

saying these in an interview costs you the question

  • Wants CI to inject scenarios through an environment variable
  • Allows --vus on a suite built from a scenarios map
  • Treats moving a threshold into K6_ as a harmless refactor
  • Relies on the per-machine default config.json in CI
  • Assumes the override warning always appears in the log
  • Thinks banning --duration alone protects a scenarios map