skip to content

Rolling k6 out to several teams, what must you standardise because a k6 test is ordinary JavaScript?

level: principalimportance: should knowfreq 42%

answer

  1. the tool standardises little for you
  2. same binary on every runner
  3. one shared module layer
  4. no threshold means no verdict
  5. executor names are already fixed

basics

~20 s

Standardise the binary every runner resolves to, the shared module layer teams import, and a rule that every test declares thresholds, since k6 exits zero when none exist. The executor vocabulary standardises itself: only six names are legal.

solid answer

~50 s

Because a k6 test is a JavaScript module rather than something the tool authors, nothing is standardised for you except what the binary refuses to accept. Three things need a decision. **The binary**: stock, or a build with extensions — and every laptop and runner must resolve to the same one. **The shared module layer**: tests reuse by ES `import`, so unless one repository owns the auth helpers, base URLs, tags and a common `options` fragment, every team writes its own. **A threshold policy**: k6 exits 99 only when a declared threshold is breached, and supplies no default, so a test with none always exits zero — "every test declares thresholds" has to be enforced in review or lint. One thing standardises itself: `executor` is a string with exactly six legal values in k6 v2, and an unrecognised one fails configuration parsing before any load runs.

code

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

const teamDefaults = {
  thresholds: { http_req_failed: ['rate<0.01'] },
};

export const options = {
  ...teamDefaults,
  vus: 5,
  duration: '10s',
};

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

go deeper

for a junior

The point to remember: k6 does not impose a house style on tests. Anything shared between teams — helpers, options fragments, conventions — exists because someone built and published it.

for a middle

Be able to name what the binary enforces versus what habit enforces. Executor names and the exit contract are fixed; test structure, shared modules and the result destination are not.

for a senior

Show you have run this rollout: pin the binary, seed a shared module layer early, and add a mechanical check that a test declares thresholds, since k6 exits zero when none exist.

for a principal

Argue where the line sits. Too little standardisation gives you five dialects and incomparable results; too much rebuilds the rigid authored-plan model you chose k6 to escape, without its tooling.

## Why this is a real question for k6 When a tool authors the test for you, its own vocabulary is the standard: everyone's artefact has the same shape because the tool would not let it be otherwise. k6 makes the opposite bet. The test is a JavaScript module, the configuration is an exported object, and reuse is `import`. That is a great deal of freedom, and freedom across five teams becomes five conventions unless somebody decides otherwise. So the adoption question is not "can k6 do this?" — it can — but "what will diverge if nobody owns it?" ## The four decisions to own 1. **Which binary.** If any team imports a module under `k6/x/`, the organisation now needs a built binary, published somewhere, resolved identically by every CI runner and every laptop. If nobody needs an extension, standardise on "the stock release, at this version" and say so explicitly — an unstated default is still a decision, just an unowned one. 2. **The shared module layer.** Decide which repository holds the modules every test imports: authentication, base URLs, a tagging convention, and a house `options` fragment teams spread into their own. Without it, five teams solve the same login flow five times and none of the solutions improve. 3. **A threshold policy.** k6 renders a verdict only when a threshold is declared. Nothing forces one, and a script with an empty `thresholds` block runs happily and exits zero. "Every test declares thresholds" therefore has to live in a review checklist or a lint rule, because the tool will never raise it. 4. **Where results go.** The run itself prints a terminal summary. Anything durable — a file, a dashboard, a time-series backend — is a choice, and if it is not made centrally each team makes a different one and nothing is comparable across them. ## What standardises itself - **The scheduling vocabulary.** In k6 v2 the `executor` key is a plain string, and exactly **six** executor names are registered in the binary. An unrecognised value fails configuration parsing before any load is generated, so no team can invent a seventh. This is the one axis you do not have to police. - **The exit contract.** A breached threshold exits **99** everywhere, on every machine, in every version of the same binary. Pipelines written against it do not need per-team variants. - **The module boundary.** Anything not in the binary's module set fails at load, so a team cannot quietly acquire a capability the others lack — the failure is loud and immediate. ## Where the effort actually lands | area | standardised by the tool | left to you | |---|---|---| | scheduling names | yes — six legal `executor` values | nothing; the set is closed | | verdict mechanics | yes — a breach exits 99 | whether a threshold exists at all | | test structure | no | a shared module layer and where it lives | | runtime identity | no | which binary build every runner resolves to | | result destination | no | one sink, chosen centrally | The pattern is worth naming: k6 standardises the things the binary can refuse, and standardises nothing that is merely a habit. Everything in the right-hand column is a habit until you write it down. ## The judgment call There is no single right answer here, and the trade is genuine. Standardise too little and you get five dialects, incomparable results, and a script that runs on one runner and not another. Standardise too much — a mandated wrapper library every test must go through, a bespoke internal CLI in front of `k6 run` — and you have quietly rebuilt the authored-plan model you chose k6 to avoid, with none of the tooling and all of the rigidity. The defensible middle is usually **pin the binary hard, share modules generously, mandate the verdict, and leave everything else to the teams** — because each of those lands somewhere different: - **The binary** is where divergence causes outages: a script that loads on one runner and not another is a pipeline failure, not a style disagreement. - **The shared layer** is where duplication compounds: the same login flow written five times never improves in any of the five. - **The verdict** is where silence looks like success: a test with no threshold reports green forever and nobody notices. - **Test structure, naming and file layout** are where local judgment costs little and central control buys nothing. - **The result destination** sits in between: cheap to unify early, painful once every team has a different one. Whichever line you draw, draw it before the second team starts — retrofitting a shared module layer across tests that already exist is far more expensive than seeding one, and asking a team to add thresholds to a suite that has been "green" for six months is a conversation nobody enjoys.

  • How would you enforce that every k6 test declares thresholds?
    In review plus a mechanical check, because k6 never will. A small lint step that loads the script's exported `options` and fails when `thresholds` is missing or empty catches it before merge, which is far cheaper than discovering six months later that a green stage asserted nothing.
  • What is the risk of building an internal wrapper CLI around k6 run for consistency?
    You gradually recreate the authored-plan model k6 was chosen to avoid. Teams lose the ability to read a test as plain JavaScript, the wrapper becomes an unowned dependency, and debugging gains a layer. Prefer shared importable modules, which teams can read and bypass, over a mandatory front door.
  • Which of these decisions can safely be deferred?
    Test structure and naming conventions — they cost little to unify later and central control buys little. The binary and the threshold policy cannot be deferred: divergent binaries break pipelines, and tests without thresholds accumulate a backlog of runs that never asserted anything.

saying these in an interview costs you the question

  • Assuming k6 enforces a house test structure across teams
  • Believing each team can register its own executor names
  • Thinking a k6 test without thresholds still fails on a bad run
  • Mandating an internal wrapper CLI in front of every k6 run
  • Treating the k6 version as enough to make runs reproducible
  • Leaving the result destination to each team and expecting comparable numbers