skip to content

Scenario Map Keys

The scenarios option is a map whose keys name workloads that run in one test, each with its own executor and function. Interviewers use it to see if you can compose several load patterns.

on this pageshow

explore

questions

6

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%

answer

  1. the key is not decoration
  2. map, not array
  3. one key has no default
  4. letters, digits, underscore, dash only

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.

solid answer

~40 s

In k6 v2, `options.scenarios` is a JavaScript object rather than an array, and the property name on the left is the scenario's identity — there is no `name` key inside the entry. k6 validates that name against `^[0-9a-zA-Z_-]+$`, so `checkout_v2` and `smoke-1` are fine while `checkout flow` and `checkout.v2` are rejected, and it reuses the name in the run header, in the per-scenario summary section, and as the value of the `scenario` tag. The only required key inside an entry is `executor`, naming one of k6 v2's six executors; omit it and k6 fails with `scenario '<name>' doesn't have a specified executor type` and exits 104 before sending a request. Everything else that is shared across executors has a default: `startTime` `0s`, `gracefulStop` `30s`, `exec` `"default"`, `env` and `tags` empty.

code

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

export const options = {
  scenarios: {
    browse_catalog: {
      executor: 'constant-vus',
      vus: 20,
      duration: '30s',
    },
    checkout: {
      executor: 'per-vu-iterations',
      exec: 'checkout',
      vus: 5,
      iterations: 10,
    },
  },
};

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

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

go deeper

for a junior

Recall that options.scenarios is a map, the key is the scenario name, and every entry must set executor. Knowing the default of exec is "default" is enough at this stage.

for a middle

Explain what the name is reused for — header lines, the per-scenario summary section, the scenario tag, the (startTime, name) sort order — and name the shared keys with their defaults.

for a senior

Show that a bad name or a missing executor is caught at config time and exits 104 before traffic, and that entries are decoded strictly so a stray key fails rather than being ignored.

for a principal

Weigh scenario names as a public interface: they land in dashboards and tag filters, the charset is restricted, and renaming one silently breaks every saved query built on the scenario tag.

## `scenarios` is a map, and the key is the name In k6 v2 a script configures its workloads by exporting an `options` object with a `scenarios` property. That property is a plain JavaScript **object** (a map), not an array. Each property of that object is one **scenario** — one independently scheduled workload — and **the property name is the scenario's name**. There is no `name` field inside an entry to set; k6 fills the name in from the map key while it parses the map. Because it is a map rather than a list, uniqueness is free: writing the same key twice simply leaves the last one. Every scenario in the map runs inside the same `k6 run` process, on the same script, under the same root-level `options`. ```javascript export const options = { scenarios: { browse_catalog: { executor: 'constant-vus', vus: 20, duration: '1m' }, checkout: { executor: 'per-vu-iterations', exec: 'checkout', vus: 5, iterations: 10 }, }, }; ``` ## What k6 does with the name The key is not decoration — k6 threads it through the whole run: - the run header prints one line per scenario, `* <name>: <description>`; - the end-of-test summary gets a `SCENARIO: <name>` section per scenario; - k6 attaches a `scenario` tag whose value is the name to the samples that scenario emits; - k6 sorts scenarios by `(startTime, name)`, so the name is the tie-break when two scenarios start together; - configuration errors are reported per name: `scenario <name> has configuration errors: ...`. Because the name travels into output and tags, k6 restricts it. The name is matched against the regular expression `^[0-9a-zA-Z_-]+$` — digits, latin letters, underscores and dashes only. A name with a space, a dot, a slash or an accented character fails validation with *the scenario name should contain only numbers, latin letters, underscores, and dashes*. ## The one required key Every entry must declare `executor`, a string naming which of k6 v2's six executors schedules that scenario: `shared-iterations`, `per-vu-iterations`, `constant-vus`, `ramping-vus`, `constant-arrival-rate` or `ramping-arrival-rate`. Two distinct failures exist here, and both are configuration errors that stop the run with exit code **104** (`InvalidConfig`) before any traffic is generated: 1. the key is missing entirely — `scenario '<name>' doesn't have a specified executor type`; 2. the key names something k6 does not know — `unknown executor type '<value>'`. In k6 v2 that includes `externally-controlled`, which the v2.0.0 release removed. ## The shared keys every entry accepts Beyond `executor`, k6 defines a common block of keys that every executor accepts, whichever one you named: | key | type | default | what it does | |---|---|---|---| | `executor` | string | — (required) | which of the six executors schedules this scenario | | `startTime` | duration string | `"0s"` | offset from the start of the run at which this scenario begins | | `gracefulStop` | duration string | `"30s"` | how long in-flight iterations may run past the scenario's end | | `exec` | string | `"default"` | the exported function this scenario's VUs call | | `env` | object | `{}` | environment variables overlaid on `__ENV` for this scenario only | | `tags` | object | `{}` | tags added to the samples this scenario emits | | `options` | object | `{}` | scenario-scoped extras, currently browser options | Everything else in an entry belongs to the executor you named, and each executor defines a different set. ## Entries are parsed strictly k6 does not merge an entry loosely into a struct. It reads the map, looks at each entry's `executor` string, and hands that entry's raw JSON to the matching executor's config constructor, which decodes with `DisallowUnknownFields`. The practical consequence is that a key which is neither one of the shared keys above nor one of the named executor's own keys is a **hard configuration error**, not a silently ignored field. ## Common misreadings - **"`scenarios` is an array of objects with names inside."** It is a map; the key is the name. - **"Any string works as a scenario name."** Spaces and dots fail the name regex. - **"`executor` is optional and defaults to something."** It is the one key with no default. - **"An entry with a stray key just ignores it."** Inside a scenario entry it fails the run. - **"Each scenario is a separate k6 run."** They all run in one process and one summary.

  • What does k6 do if two scenarios in the map name the same `exec` function?
    Nothing special — that is legal and common. Both scenarios call the same exported function, each with its own executor, `startTime`, `env` and `tags`, and k6 keeps their samples apart through the `scenario` tag and the per-scenario summary sections. `exec` defaults to `"default"`, so scenarios that omit it all share the default function.
  • Where does k6 get the scenario name from when the script never writes `scenarios` at all?
    It invents one. When a script sets only root-level shortcut options such as `vus` and `duration`, k6 derives a single scenario named `default` from them, so the header and the `scenario` tag both read `default`. That name is the constant `DefaultScenarioName` in k6, and it is why so many summaries show a scenario nobody wrote.

saying these in an interview costs you the question

  • Calling options.scenarios an array of scenario objects
  • Expecting a name field inside the entry instead of the map key
  • Assuming executor has a default and can be omitted
  • Using a scenario name with spaces or dots
  • Believing each scenario runs as its own k6 process
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

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

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