How do you make a k6 scenario run an exported function other than the default one?
answer
- a name, not a reference
- string value on the scenario
- defaults to 'default'
- validated before the run starts
basics
~20 sSet that k6 scenario's exec key to the name of the exported function, as a string: exec: 'addToCart'. It defaults to 'default', and k6 rejects the configuration before the run starts if no export by that name exists.
solid answer
~40 sEvery k6 scenario takes a generic `exec` property whose value is the **name** of an exported function, written as a string -- `exec: 'addToCart'`, not `exec: addToCart`. It defaults to `"default"`, which is why a script with one default export never has to set it. k6 collects every exported value that is a function when it loads the script (skipping `options`), and validates each scenario's `exec` against that set before the run begins; an unresolved name fails the configuration with `executor <scenario>: function '<name>' not found in exports` and nothing runs. The named function is called exactly like `default` would be, including receiving whatever `setup()` returned, so in k6 v2 a script can be built entirely from named exports with no default export at all.
code
javascript · 31 linesimport http from 'k6/http';
import { check, sleep } from 'k6';
const BASE = 'https://quickpizza.grafana.com';
const headers = {
'Content-Type': 'application/json',
Authorization: 'Token abcdef0123456789',
};
export const options = {
scenarios: {
browsers: { executor: 'constant-vus', vus: 5, duration: '30s', exec: 'browse' },
buyers: { executor: 'constant-vus', vus: 1, duration: '30s', exec: 'addToCart' },
},
};
export function browse() {
const res = http.get(`${BASE}/`);
check(res, { 'menu page loaded': (r) => r.status === 200 });
sleep(1);
}
export function addToCart() {
const res = http.post(
`${BASE}/api/pizza`,
JSON.stringify({ maxCaloriesPerSlice: 1000, mustBeVegetarian: false }),
{ headers }
);
check(res, { 'pizza added to cart': (r) => r.status === 200 });
sleep(1);
}go deeper
Know that a scenario can run a function other than the default one, and that you point at it by writing its name in quotes under the exec key.
Explain that exec is a name looked up among the script's exported functions, that it defaults to default, and that k6 validates it before the run rather than at the first iteration.
Show judgment about when splitting a journey across exported functions is right, and be ready to read the not-found-in-exports error back to a colleague and say what caused it.
Weigh one script with several exec targets against several scripts. The single-file shape keeps shared helpers honest but couples release cycles; decide which cost your organisation would rather carry.
## The `exec` key Every k6 scenario has a generic `exec` property. Its value is a **string**: the name of a function the script exports. Its default is `"default"`, which is why a script with a single default export and no `exec` anywhere works without you ever writing the key. ```javascript export const options = { scenarios: { buyers: { executor: 'constant-vus', vus: 5, duration: '1m', exec: 'addToCart' }, }, }; export function addToCart() { // this is the VU code for the `buyers` scenario } ``` Two things about that value are worth stating precisely, because both are commonly got wrong: - it is a **name**, not a reference -- you write `exec: 'addToCart'`, in quotes, not `exec: addToCart`; - it names an **export**, not a file -- k6 looks the name up in the exports of the script it is already running, and never loads a second file for it. ## What counts as an exported function When k6 loads the script it walks the module's exported names and keeps every one whose value is a function. The `options` export is deliberately excluded, since it is configuration. Everything else -- `default`, `setup`, `teardown`, `handleSummary`, and any function you export under a name of your own -- ends up in that set and is therefore a legal `exec` target. If the set is empty, k6 stops with `no exported functions in script` before any traffic is generated. Because the lookup runs against the **main module's own exports**, a function defined in an imported file is not reachable by name unless the main script re-exports it. Writing `export { addToCart } from './cart.js';` puts the name into the main module's export list and makes it a valid `exec` target; importing it without re-exporting does not. ## When the name does not resolve k6 validates every scenario's `exec` against that set **before the run starts**, not lazily at the first iteration. A name that does not resolve produces a configuration error naming both the scenario and the missing function: ``` executor buyers: function 'addToCart' not found in exports ``` Nothing runs. This is a deliberate design choice: a typo in `exec` is caught in the first second rather than after a ramp has already been paid for. Note that it fires for a misspelling, for a function you forgot to `export`, and for an export that exists but is not callable -- a string or an object under that name is not a function, so it is not in the set. | What you write | What k6 calls | |---|---| | no `scenarios` block at all | the export named `default` | | a scenario with `exec` omitted | the export named `default` | | `exec: 'addToCart'` | the export named `addToCart` | | `exec: 'addToCart'` with no such export | nothing -- the run is rejected before it starts | ## Splitting a journey across two functions The key earns its keep when one script has to drive two different behaviours at once. Suppose a browse-then-add-to-cart journey should not run as a single mix: you want many users browsing and only a few adding to the cart. Export two functions and give each scenario its own `exec`: ```javascript export const options = { scenarios: { browsers: { executor: 'constant-vus', vus: 10, duration: '1m', exec: 'browse' }, buyers: { executor: 'constant-vus', vus: 2, duration: '1m', exec: 'addToCart' }, }, }; export function browse() { /* ... */ } export function addToCart() { /* ... */ } ``` Each scenario now runs iterations of its own function, and each iteration still means exactly what it meant before: one complete call of the named function. ## Details that follow from it 1. **Several scenarios may share one `exec`.** It is only a name lookup, so pointing two scenarios at the same exported function is legal and needs no change to the function itself. 2. **The named function gets the same argument as `default`.** k6 calls whichever function the scenario names with the value `setup()` returned, so `export function addToCart(data) { ... }` receives exactly what `export default function (data) { ... }` would. 3. **A default export is not required.** If every scenario names a function explicitly, the script needs no `default` export at all. 4. **The word "default" appears twice, meaning different things.** The implicit scenario k6 derives when you use plain root options is also called `default`. The scenario name and the function name are independent; one being `default` does not force the other to be.
- Can two k6 scenarios point their `exec` at the same function?Yes. `exec` is only a name lookup, so several scenarios may name the same exported function. Each one schedules its own iterations of it and the function itself needs no change; nothing about the code has to know which scenario invoked it.
- Does a function named by `exec` receive the same argument as `default`?Yes. k6 calls whichever exported function the scenario names with the value `setup()` returned, exactly as it calls `default`. So `export function addToCart(data) { ... }` gets the same `data`, and `undefined` when the script has no `setup()`.
- What exactly does k6 do when `exec` names a function that is not exported?It fails configuration validation before any virtual user starts, with `executor <scenario>: function '<name>' not found in exports`. The check happens up front rather than at the first iteration, so a typo costs a second rather than a whole ramp.
saying these in an interview costs you the question
- Writes exec as a bare identifier instead of a quoted string
- Thinks exec names a second script file to load
- Expects k6 to fall back to the default export when exec is wrong
- Believes every k6 script must have a default export
- Confuses the scenario named default with the function named default