skip to content

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