In a k6 script, what does the default exported function do, and what counts as one iteration?
answer
- the body a virtual user repeats
- one call, start to finish
- export default is the VU stage
- argument carries setup()'s return value
basics
~20 sk6's default exported function is the VU code: one virtual user runs it from its first line to its last, and that single start-to-finish call is one iteration. When it returns, the VU calls it again.
solid answer
~40 sIn k6 v2 a script must export at least one callable function, and `export default function (data) { ... }` is the conventional one. Its body is the VU code -- the requests, the `check()` calls, the `sleep()` calls that make up one simulated user journey. One complete call of that function, top to bottom, is what k6 calls an **iteration**; when it returns the same virtual user calls it again, and again, for as long as the run lasts. The `data` argument is whatever `setup()` returned, or `undefined` if the script has no `setup()`. If a script exports no callable function at all, k6 refuses to start it with `no exported functions in script`.
code
javascript · 27 linesimport http from 'k6/http';
import { check, sleep } from 'k6';
// init code: evaluated once per VU, not on every iteration
const BASE = 'https://quickpizza.grafana.com';
const headers = {
'Content-Type': 'application/json',
Authorization: 'Token abcdef0123456789',
};
export default function (data) {
// `data` is whatever setup() returned; undefined when there is no setup()
// step 1 - browse the menu
const menu = http.get(`${BASE}/`);
check(menu, { 'menu page loaded': (r) => r.status === 200 });
sleep(1);
// step 2 - add the recommended pizza to the cart
const order = http.post(
`${BASE}/api/pizza`,
JSON.stringify({ maxCaloriesPerSlice: 1000, mustBeVegetarian: false }),
{ headers }
);
check(order, { 'pizza added to cart': (r) => r.status === 200 });
sleep(1);
}go deeper
Be able to point at the exported function and say the body is the VU code, and that one complete call of it is one iteration. Knowing that k6 calls it again when it returns is enough at this stage.
Explain the split: module top level is evaluated once per VU, the function body runs once per iteration. Say what the data parameter carries and what happens when a script exports nothing callable.
Show that you design the body deliberately -- what belongs in one iteration versus what should be lifted out of it, and how splitting a journey across functions changes what the run is actually counting.
Frame the iteration body as the unit your whole team reads results in. Whether one iteration means one journey or one request decides how every later number is interpreted, so it is worth standardising.
## What the default exported function is A k6 test script is an ES module, and k6 does **not** re-run that module from top to bottom over and over. It evaluates the module once to prepare a virtual user, and then repeatedly calls one **exported function**. That function is the *VU stage*: it holds the requests, the `check()` calls, the `sleep()` calls -- the whole journey you want one simulated user to perform. By convention that function is the module's default export: ```javascript export default function (data) { // everything one virtual user does, once } ``` In k6 v2 the only hard requirement is that the module exports at least one callable function. k6 collects every exported value that happens to be a function -- the `options` export is deliberately skipped, because it is configuration rather than code -- and if that set comes out empty the run stops before a single request is sent, with `no exported functions in script`. The name `default` is not magic in itself: it is simply the name k6 looks for when nothing has told it to look for another one. ## One call is one iteration The word **iteration** in k6 means exactly one call of that function, from its first statement to its last. Not one request, not one virtual user, not one second of wall clock: one full pass through the function body. When the call returns, the virtual user is neither stopped nor thrown away. It calls the same function again, and that is iteration two. A VU that lives for thirty seconds may complete hundreds of iterations or three, depending only on how long one pass takes and on what the test configuration asks for. The function may also be `async`. `export default async function () { ... }` is valid in k6 v2, and k6 waits for the returned promise to settle before it treats the iteration as finished -- which is what makes the `await`-based browser API usable inside an iteration at all. | Term | What it names in k6 | |---|---| | VU | one virtual user, holding its own evaluated copy of the script | | iteration | one start-to-finish call of the exported VU function | | `default` | the export k6 calls when nothing names a different one | | `data` | the parameter carrying whatever `setup()` returned | ## What goes inside the body, and what does not Two things belong inside the function body and nowhere else: - **the work you want measured** -- the HTTP, gRPC or WebSocket calls the simulated user makes; - **the per-pass logic** -- building a payload, reading a response, choosing which branch of the journey to take this time. Anything that should happen once, before any traffic, belongs outside the body at the module's top level. Anything you put inside the body is paid for on every iteration, by every VU, for the whole run. ## A worked iteration: browse, then add to cart The boundary is easiest to see with a two-step journey. One iteration is *both* steps -- browsing the menu and adding an item to the cart -- because both live inside one function body: ```javascript export default function (data) { const menu = http.get(`${BASE}/`); // step 1 check(menu, { 'menu loaded': (r) => r.status === 200 }); sleep(1); const order = http.post(`${BASE}/api/pizza`, body, { headers }); // step 2 check(order, { 'item added to cart': (r) => r.status === 200 }); sleep(1); } ``` Split those two steps into two separate exported functions and you have changed what the test means: k6 would then be counting two independent iterations rather than one two-step journey. ## What k6 does at the boundary Between the return of one call and the start of the next, k6 does a small amount of housekeeping. It gives the virtual user a **fresh cookie jar**, unless the script sets `noCookiesReset: true`, and it may tear down idle connections depending on the run's configuration. It does **not** reset variables the script itself declared at module level. State you deliberately keep is kept; state the HTTP layer was keeping for you is not. ## The `data` parameter k6 calls the function with exactly one argument, and it is the value the script's `setup()` function returned, handed to every VU. When the script has no `setup()`, the argument is simply `undefined`. Declaring the parameter costs nothing, so `export default function (data)` is the usual shape even in scripts that never look at it. ## Mistakes that surface in review 1. **Counting requests as iterations.** A body containing four requests still produces one iteration per pass, not four. 2. **Expecting the module to re-evaluate.** Top-level code does not run again between iterations; only the function body does. 3. **Assuming the VU is rebuilt.** The same virtual user, with the same already-evaluated module, makes the next call.
- Does a k6 script have to export a function actually named `default`?No. k6 needs at least one exported callable function, and `default` is only the name it reaches for when nothing points it elsewhere. A scenario's `exec` key can name any exported function, so a script made entirely of named exports runs fine as long as every `exec` resolves to one of them.
- Can the k6 default function be declared `async`?Yes. `export default async function () { ... }` is supported in k6 v2, and k6 waits for the returned promise to settle before the iteration is considered finished -- that is what lets the `await`-based browser API run inside an iteration. Note that `sleep()` from `k6` blocks the event loop, so pending promises cannot settle while it waits.
saying these in an interview costs you the question
- Counts each HTTP request in the function as its own iteration
- Thinks the default function runs once for the whole test
- Believes k6 re-evaluates the whole script file every iteration
- Cannot say what the function's data parameter holds
- Assumes k6 builds a brand-new virtual user for each iteration