skip to content

Declared Settings

How a k6 run is configured: one exported options object, five places a value can come from, and a scenarios map naming each workload. Interviewers probe configuration-as-code here.

on this pageshow

explore

questions

16

In k6, what is the exported `options` object and how does it configure a test run?

level: juniorimportance: must knowfreq 82%

answer

  1. the script is its own config file
  2. a named export, read at init
  3. export const options = { ... }
  4. root keys: vus, duration, stages, scenarios

basics

~20 s

k6 has no separate configuration file format. A k6 script exports an object named options, k6 reads it once at init, and its root keys - vus, duration, stages, scenarios, thresholds, tags - become the run configuration.

solid answer

~40 s

A k6 script configures itself. You add a named export called `options` - idiomatically `export const options = { ... }` - and k6 evaluates the script once before any virtual user exists, then decodes that object into the run configuration. Root keys include `vus`, `duration`, `stages`, `scenarios`, `thresholds`, `tags`, `rps`, `discardResponseBodies` and `summaryTrendStats`. Because it is ordinary JavaScript sitting in the script file, load settings are reviewed and version-controlled alongside the code they exercise. Many of the same settings also have a `k6 run` flag - `--vus`/`-u`, `--duration`/`-d`, `--stage`/`-s`, `--tag` - so a committed script can be run once at a different size without editing the file. A few keys, notably `thresholds` and `scenarios`, have no flag at all.

code

javascript · 14 lines
javascript
import http from 'k6/http';

export const options = {
  vus: 10,
  duration: '5m',
  rps: 200,
  discardResponseBodies: true,
  tags: { service: 'checkout' },
  thresholds: { http_req_duration: ['p(95)<500'] },
};

export default function () {
  http.get('https://quickpizza.grafana.com/');
}

go deeper

for a junior

Be able to write the export from memory and name what vus, duration and stages do. Knowing that the settings live in the script itself, not in a separate config file, is most of the answer at this level.

for a middle

Explain the mechanics: k6 evaluates the script once before any VU exists, serialises the exported value and decodes it, so the object must be JSON-shaped data and is read once per run rather than per VU.

for a senior

Show you know which keys have no command-line flag, and why that shapes how a team runs k6 in CI. Being able to say that thresholds and scenarios must be committed is the production-relevant half.

for a principal

The tradeoff is what the committed object should fix and what the invocation is allowed to vary. Fixing too much makes one-off runs need code changes; fixing too little makes runs unreproducible from the repository alone.

## The script is the configuration k6 does not read a separate settings file before it reads your test. A k6 test is a JavaScript module, and one of the things that module exports is an object named `options`. Everything the run needs to know that is not test logic - how many virtual users, for how long, what to tag the metrics with, what to assert - is a key in that object, in the same file, in the same commit as the requests it configures. The name is the contract. k6 looks up the module export called `options`: ```javascript export const options = { vus: 10, duration: '30s' }; ``` `export let options = { ... }` behaves identically, and in base compatibility mode `module.exports.options = { ... }` does too. `const` is convention, not a requirement. ## When k6 reads it k6 evaluates the script once, in a throwaway init runtime, **before any virtual user exists**. It takes the exported value, serialises it to JSON, and decodes that JSON into its own internal options structure. Three consequences follow, and they explain most surprises: 1. The object may be **computed** rather than written as a literal, because it is ordinary JavaScript that runs before the decode - the value just has to exist by the time the module finishes evaluating. 2. It must reduce to **JSON-shaped data**. A value that JSON cannot represent is not configuration k6 can read, so the object holds plain objects, arrays, strings, numbers and booleans and nothing more. 3. It is read **once for the whole run**, not per VU and not per iteration. A computed `options` therefore cannot vary between virtual users: every VU is created after the decode has already happened. ## The root keys The object is flat: keys sit at its top level, in camelCase. The ones you meet first: - **`vus`** - how many virtual users to run concurrently. Defaults to 1. - **`duration`** - how long the run lasts, as a duration string such as `'30s'` or `'5m'`. - **`stages`** - an array of `{ duration, target }` steps, for a run whose VU count changes over time. - **`scenarios`** - a map of named, independently configured workloads, for anything the three keys above cannot express. - **`thresholds`** - the pass rules the run is judged against. - **`tags`** - an object of key/value pairs attached to every metric sample the run emits. - **`rps`** - a cap on HTTP requests per second shared across all VUs; `0`, the default, means unlimited. - **`discardResponseBodies`** - `false` by default; set it to `true` and k6 reads response bodies without keeping them. - **`summaryTrendStats`** - which statistics the end-of-test summary prints for timing metrics. There are many more - `httpDebug`, `insecureSkipTLSVerify`, `maxRedirects`, `noConnectionReuse`, `setupTimeout`, `userAgent`, `systemTags` and others - but the list above covers almost every real script. ## The same setting, from the command line Most root keys have a matching `k6 run` flag, and the flag name is the kebab-case form of the camelCase key. Two of them are deliberately singular, because the flag is repeatable while the key takes a collection: | `options` key | `k6 run` flag | note | |---|---|---| | `vus` | `--vus`, `-u` | default `1` | | `duration` | `--duration`, `-d` | | | `iterations` | `--iterations`, `-i` | | | `stages` (array) | `--stage`, `-s` | flag is singular and repeatable | | `rps` | `--rps` | `0` means unlimited | | `tags` (object) | `--tag NAME=VALUE` | flag is singular and repeatable | | `discardResponseBodies` | `--discard-response-bodies` | | | `summaryTrendStats` | `--summary-trend-stats` | | | `thresholds` | *(no flag)* | script or a `--config` JSON file only | | `scenarios` | *(no flag)* | script or a `--config` JSON file only | So a script that declares `vus: 10, duration: '5m'` can still be run once as `k6 run --vus 1 --duration 10s script.js` for a smoke check, without touching the file. What you cannot do from the command line is add a threshold or a scenario: those two keys have no flag in k6 v2, which is a good reason to think of the exported object as the primary home for configuration and the flags as the escape hatch. ## What is different in k6 v2 Cloud settings live under the root **`cloud`** key. The older `options.ext.loadimpact` block was removed in k6 v2.0.0 and is no longer read, so a script carrying one is silently configuring nothing. Feature flags are the one documented exception to "options configures the run": a `features` key in the exported object is not honoured, and k6 logs a warning telling you to use `--features`, `K6_FEATURES` or the JSON config file instead.

  • Does k6 require `export const options`, or will another export form work?
    k6 looks up the module export whose name is `options`; the declaration form is yours. `export const options = { ... }` is the convention, `export let options = { ... }` is equivalent, and in base compatibility mode `module.exports.options = { ... }` works too. Renaming the export is what breaks it - k6 will simply find no options and run with defaults.
  • Which k6 root options keys cannot be set from a `k6 run` flag?
    `thresholds`, `scenarios` and `cloud` have no command-line flag in k6 v2. They can only come from the script's exported `options` object or from a JSON file passed with `--config`. That is why a k6 suite's pass rules and its workload shape effectively have to be committed rather than improvised at the prompt.
  • Where do cloud settings go in a k6 v2 options object?
    Under the root `cloud` key. The `options.ext.loadimpact` block that older k6 material shows was removed in k6 v2.0.0. `ext` still parses as a root key, so an `ext.loadimpact` block does not fail the run - it is simply ignored, which makes it a quiet way to lose configuration when porting an old script.

saying these in an interview costs you the question

  • Thinks k6 needs a separate YAML or XML configuration file
  • Says k6 re-reads the options object once per iteration
  • Assumes every options key has a matching k6 run flag
  • Puts cloud settings under ext.loadimpact, removed in k6 v2.0.0
  • Calls the CLI flag --stages; k6's flag is singular --stage
open as a page

In a k6 script, what do the keys of the `options.scenarios` object mean, and what must each entry declare?

level: juniorimportance: must knowfreq 72%

basics

~20 s

Every key in k6's options.scenarios object is that scenario's name, unique within the script and limited to letters, digits, underscores and dashes. Each entry must declare executor; exec, startTime, gracefulStop, env and tags all have defaults.

open as a page

In k6, which five layers can set the same option, and in what order do they override each other?

level: middleimportance: must knowfreq 70%

basics

~10 s

k6 resolves each option through five layers, lowest to highest: built-in defaults, a JSON config file, the script's exported options, a K6_ environment variable, then the command-line flag. The CLI flag always wins.

open as a page

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

level: seniorimportance: must knowfreq 58%

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.

open as a page

In a k6 scenarios map, what is `startTime` measured from, and how do you make two scenarios run back to back?

level: seniorimportance: must knowfreq 64%

basics

~20 s

startTime is an absolute offset from the start of the k6 run, not from the previous scenario's end. k6 launches every scenario at once and each waits out its own offset, so sequencing is arithmetic you do yourself.

open as a page

Which k6 option layers can supply a scenarios map, and which layers cannot reach it at all?

level: middleimportance: should knowfreq 44%

basics

~20 s

A k6 scenarios map can only come from the script's exported options or a --config JSON file. No K6_SCENARIOS variable or CLI flag exists, so the top two layers can only discard a map, never supply one.

open as a page

In k6, what happens if a key in the exported `options` object is misspelled?

level: middleimportance: should knowfreq 52%

basics

~20 s

k6 logs one warning - There were unknown fields in the options exported in the script - and runs anyway with the default for the setting you meant. A misspelled root key never stops the run, so the run silently ignores it.

open as a page

In k6, what does a script that declares only root-level `vus` and `duration`, with no `scenarios`, actually run?

level: middleimportance: should knowfreq 58%

basics

~10 s

k6 always runs a scenarios map. When a script sets only root-level shortcuts, k6 derives one scenario named default from them: duration plus vus becomes constant-vus, stages becomes ramping-vus, and iterations becomes shared-iterations.

open as a page

Which per-scenario keys let one k6 run drive several exported functions and keep their results separable?

level: middleimportance: should knowfreq 52%

basics

~10 s

Three keys in the k6 scenario entry: exec names the exported function that scenario's VUs call, env overlays __ENV for that scenario only, and tags attaches key-value pairs to the samples the scenario emits.

open as a page

Why does a k6 scenario with `duration: '10s'` often keep running for longer than ten seconds?

level: middleimportance: should knowfreq 55%

basics

~20 s

Because of gracefulStop, a per-scenario key that defaults to 30s on every k6 executor. At the end of the declared duration k6 stops starting new iterations but lets in-flight ones finish, cutting whatever is still running when gracefulStop expires.

open as a page

In k6, what happens when an exported `options` object sets both `stages` and `scenarios`?

level: seniorimportance: should knowfreq 45%

basics

~20 s

k6 refuses to start. It reports that using stages and scenarios options simultaneously is not allowed and exits 104, invalid configuration, before any request is sent - because stages is shorthand that k6 would have to turn into a scenario itself.

open as a page

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%

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.

open as a page

For a k6 suite in CI, which settings belong in the exported `options` object rather than on the command line?

level: principalimportance: should knowfreq 40%

basics

~20 s

k6 settles part of it: thresholds, scenarios and cloud have no k6 run flag, so they can only live in the script or a --config JSON file. The flags carry the size knobs - vus, duration, stage, tag.

open as a page

In k6, what does `exec.test.options` give you that the exported `options` object does not?

level: middleimportance: nice to knowfreq 38%

basics

~20 s

exec.test.options, from the k6/execution module, is the consolidated and derived configuration the run is actually using - command-line overrides included - as a read-only object. The exported options object is only what the script declared.

open as a page

Which file does k6's --config layer read by default, and when does a missing file fail the run?

level: seniorimportance: nice to knowfreq 33%

basics

~20 s

k6 reads config.json from the operating system's configuration directory on every run and ignores it silently when absent. --config or K6_CONFIG names a different path; if that named file is missing, the run exits 104.

open as a page

What happens when a k6 `options.scenarios` entry carries a key that its executor does not define?

level: seniorimportance: nice to knowfreq 38%

basics

~20 s

It is fatal. k6 decodes each scenario entry with unknown fields disallowed, so a key that is neither a shared scenario key nor one of the named executor's own keys fails config parsing and exits 104 before any traffic is sent.

open as a page