k6
The scriptable load tester where scenarios are JavaScript and pass/fail is expressed as thresholds on metrics. Asked because it fits load testing into CI, which is where interviewers want performance checks to live.
on this pageshowhide
explore
- Verdict Gating27 questions
- Soft Signals10 questions
- Binding Rules12 questions
- Run Consequences5 questions
- Executor Choice17 questions
- Bounded Users8 questions
- Rate Bound9 questions
- Script Anatomy25 questions
- Code Regions15 questions
- Data Scope10 questions
- Declared Settings16 questions
- Value Origins10 questions
- Workload Shape6 questions
- Metric Model15 questions
- Sample Kinds9 questions
- Dimensions6 questions
- Transport Surface15 questions
- Request Helpers5 questions
- Specialised Clients10 questions
- Measurement Delivery13 questions
- Closing Report9 questions
- Continuous Streams4 questions
- Runtime and Extension19 questions
- Module Namespace10 questions
- Script Engine9 questions
- Automation Fit14 questions
- Headless Invocation10 questions
- Peer Comparison4 questions
questions
161 · 9 sectionsIn k6, what happens to the running iteration when a check() condition evaluates to false?
basics
~10 sNothing halts. k6 records the failure on its built-in checks metric, check() returns false, and the iteration carries straight on to the next statement. The run's exit status is unaffected.
In k6, how do you call check() from the k6 module, and what does each argument do?
basics
~20 sk6's check(), from the k6 module, has the signature check(val, sets, [tags]): a value, an object whose keys are check names and whose values are conditions called with that value, and optional extra tags. It returns a boolean.
In k6, what exit code does a run return when one of its thresholds is breached?
basics
~20 sk6 exits with code 99 when at least one threshold is breached, and 0 when they all hold. That single integer is the whole machine-readable verdict a CI job reads; the printed summary is for humans.
In k6, why can a threshold of `checks: ['rate>90']` never pass, however many checks succeed?
basics
~20 sk6's built-in checks metric is a Rate, and the only aggregation a Rate threshold accepts is rate, which is a fraction from 0.00 to 1.00 rather than a percentage. So rate>90 is unreachable; write rate>0.9.
In k6, what does a threshold key like http_req_duration{status:200} do that a plain metric name does not?
basics
~10 sThe braces create a sub-metric: k6 registers a filtered copy of http_req_duration that receives only the samples whose tags contain status:200, and evaluates the threshold against that copy instead of the whole metric.
In a k6 `constant-arrival-rate` scenario, what do the `rate`, `timeUnit` and `duration` keys each set?
basics
~10 sIn k6 v2, rate is how many iterations the executor starts during each timeUnit period, timeUnit is that period (default 1s), and duration is how long the scenario keeps starting them.
Which k6 scenario do the root vus and iterations options build, and what does duration do there?
basics
~20 sk6 turns root vus and iterations into a single scenario named default that uses the shared-iterations executor, so iterations is the total across all VUs. A root duration set alongside them becomes that scenario's maxDuration.
In k6, how do the constant-vus and ramping-vus executors differ, and what options does each take?
basics
~20 sk6's constant-vus executor holds a fixed number of VUs for a set time and takes vus plus duration. ramping-vus moves the count through a schedule and takes startVUs, stages and gracefulRampDown. Neither accepts the other's keys.
In a k6 arrival-rate scenario, what do preAllocatedVUs and maxVUs control, and what happens when maxVUs is omitted?
basics
~10 spreAllocatedVUs is the number of VUs k6 initializes before an arrival-rate scenario starts; maxVUs is the hard ceiling that pool may grow to mid-run. Omitted, maxVUs equals preAllocatedVUs, so the pool never grows.
Which keys does k6's `ramping-arrival-rate` executor take, and what does a stage `target` mean?
basics
~20 sk6 v2's ramping-arrival-rate takes startRate, timeUnit and stages. Each stage is a target plus a duration, and the target is the arrival rate in iterations started per timeUnit that k6 ramps to linearly by the stage's end.
In a k6 script, what does the default exported function do, and what counts as one iteration?
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.
In a k6 script, which code runs in the init context, and how often does it run?
basics
~20 sEverything outside a k6 lifecycle function is init code: imports, the exported options object, open() calls, metric constructors. k6 runs it once per virtual user, in that VU's own JavaScript runtime, before that VU's first iteration.
In a k6 script, when does setup() run and how does its return value reach the other stages?
basics
~20 sk6 calls setup() once per test run, after the init stage and before any virtual user starts. Whatever it returns is JSON-encoded once and handed to the default function and to teardown() as their first argument.
Which k6 calls throw when placed in a script's init context, and what do they all have in common?
basics
~10 sAnything needing VU state throws in k6's init context: http requests and batch, new http.CookieJar(), check(), group(), a custom metric's .add(), and exec.vu, exec.instance or exec.test.options. k6 attaches VU state only after init finishes.
In k6, what is the exported `options` object and how does it configure a test run?
basics
~20 sk6 has no separate configuration file format. A k6 script exports an object named options, k6 reads it once at init, and its root keys - vus, duration, stages, scenarios, thresholds, tags - become the run configuration.
In a k6 script, what do the keys of the `options.scenarios` object mean, and what must each entry declare?
basics
~20 sEvery 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.
In k6, which five layers can set the same option, and in what order do they override each other?
basics
~10 sk6 resolves each option through five layers, lowest to highest: built-in defaults, a JSON config file, the script's exported options, a K6_ environment variable, then the command-line flag. The CLI flag always wins.
In k6, why does adding --duration on the command line discard a whole scenarios map the script declared?
basics
~10 sBecause duration, iterations, stages and scenarios form one execution group in k6: any of the four set in a higher layer clears all four from every lower layer before the new value is applied.
In a k6 scenarios map, what is `startTime` measured from, and how do you make two scenarios run back to back?
basics
~20 sstartTime 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.
Which of k6's four metric types does each built-in such as vus, http_reqs or checks use?
basics
~20 sk6 has four metric types: Counter, Gauge, Rate and Trend. Among the built-ins, vus and vus_max are Gauges, http_reqs and iterations are Counters, checks and http_req_failed are Rates, and every duration such as http_req_duration is a Trend.
Which four metric classes does k6's k6/metrics module export, and what does each keep?
basics
~20 sk6/metrics exports Counter, Gauge, Rate and Trend. Counter sums added values and reports count and rate; Gauge keeps the last value; Rate reports the share of non-zero values; Trend keeps every value, giving avg, min, max, med and p(N).
In k6, what does wrapping requests in group('name', callback) add to the metrics they emit?
basics
~10 sk6 tags every sample emitted inside the callback with a group tag holding the full nested group path joined by ::, and it emits one group_duration Trend sample timing the callback.
In k6, which three metrics add up to http_req_duration, and what does it leave out?
basics
~10 shttp_req_duration equals http_req_sending plus http_req_waiting plus http_req_receiving. It excludes http_req_blocked, http_req_connecting and http_req_tls_handshaking, so connection setup never appears in it.
In k6, what happens if you construct a k6/metrics Trend inside the default function instead of at module scope?
basics
~10 sConstructing a k6 custom metric outside the init context throws "metrics must be declared in the init context". Only .add() may run inside an iteration; the k6/metrics constructors must sit at module scope.
In k6 v2, what happens to a script that imports k6/experimental/browser, and what replaces it?
basics
~10 sThe import throws straight away with a migration message: in k6 v2 the browser module has graduated and k6/experimental/browser was removed. Import browser from k6/browser instead, and await its calls.
In k6 v2, which module provides the gRPC client, and what happens if a script imports k6/experimental/grpc?
basics
~20 sk6 v2 ships its gRPC client at the stable path k6/net/grpc. The old k6/experimental/grpc name is registered only to throw a migration error on import, so the run aborts in the init phase before any VU starts.
In k6, how do you send a JSON body with http.post(), and what does a plain object send instead?
basics
~10 sk6 picks the encoding from the body's JavaScript type: a plain object is form-encoded as application/x-www-form-urlencoded. For JSON, pass JSON.stringify(payload) as the body and set Content-Type in the params headers object.
In k6, which scenario option enables a real browser, and where in the options object does it go?
basics
~10 sSet type to 'chromium' in a scenario's own options.browser block, so the full path is options.scenarios.<name>.options.browser.type. It is per-scenario, there is no root-level browser option, and 'chromium' is the only value k6 v2 accepts.
Which k6/net/grpc Client calls must run in the init context, and which are rejected there?
basics
~20 sclient.load() and client.loadProtoset() are init-only and error elsewhere with "load must be called in the init context". client.connect(), invoke(), asyncInvoke() and close() are the reverse: they raise an init-context error and must run inside an iteration.
In k6, what must an exported `handleSummary(data)` function return, and where does each entry go?
basics
~20 sAn object whose keys are destinations and whose values are strings or ArrayBuffers. k6 sends the key stdout to standard output, stderr to standard error, and treats every other key as a file path it creates or overwrites.
In k6, how do you choose where a run streams its metrics, and which `--out` targets does v2 accept?
basics
~20 sk6 picks streaming destinations with the repeatable -o/--out flag or the K6_OUT environment variable. k6 v2 accepts json, csv, cloud, influxdb, experimental-prometheus-rw, opentelemetry, experimental-opentelemetry and web-dashboard; any other name aborts the run before it starts.
Which statistics can k6's summaryTrendStats option list, and what does it print by default?
basics
~10 sk6's summaryTrendStats accepts avg, min, med, max, count and p(N) for N between 0 and 100. It defaults to avg, min, med, max, p(90), p(95), and any list you set replaces that default entirely.
What does k6's `--out json=` write to its file, and how does `--out csv=` differ?
basics
~20 sk6's json target writes newline-delimited objects: a Metric declaration, then a Point per sample with time, value and tags. The csv target writes a fixed header of metric_name, timestamp and metric_value, then tag columns. Both gzip on a .gz path.
What does k6's summaryTimeUnit option change in the end-of-test summary?
basics
~20 sk6's summaryTimeUnit fixes the unit every duration is printed in throughout the end-of-test summary. It accepts only s, ms or us; left unset, k6 picks a readable unit per value instead, so columns may mix ns, us, ms and s.
Why does a k6 script's import of './helpers' fail when './helpers.js' works?
basics
~20 sk6 resolves import specifiers the way a browser does, not the way Node does: it never appends .js, never falls back to index.js and never searches node_modules. The extension-less path names a file that does not exist, so the load fails.
Why does importing k6/experimental/browser abort a k6 v2 run, and what replaces it?
basics
~20 sThe browser module graduated to k6/browser, and k6 v2 keeps the old path registered only as a stub that throws a migration message. The run dies while the script is loading and k6 exits 107.
Why does adding a new protocol to k6 require a compiled custom binary rather than a plugin file?
basics
~10 sk6 extensions are Go code compiled into the k6 binary; k6 has no runtime plugin loader. Either k6 provisions a prebuilt binary for you automatically, or you build one yourself with xk6 build --with.
Why does a k6 test script that imports Node's fs module fail before any VU runs?
basics
~20 sk6 executes JavaScript on Sobek, a JavaScript engine written in Go, not on Node.js. It ships no Node standard library and no node_modules resolution, so a bare specifier like fs never resolves and loading the script fails during init.
How does k6's own require() differ from an ES import statement in a test script?
basics
~20 sk6 accepts both, but require() is k6's own implementation, not Node's: it loads built-in k6 modules, local files and remote https scripts only, it exists solely in the init stage, and it takes a specifier computed at runtime.
Why does running the grafana/k6 image look like `docker run -i grafana/k6 run - < script.js`?
basics
~20 sThe grafana/k6 image sets ENTRYPOINT ["k6"], so appended arguments start at a k6 subcommand - here, run. The script lives on the host and not in the image, so the filename - makes k6 read it from standard input.
What do k6's --execution-segment and --execution-segment-sequence flags do, and why pass both?
basics
~20 sIn k6, --execution-segment names the slice of total work one process runs, and --execution-segment-sequence names the full partition every process shares. Pass both, or each instance invents its own partition and the slices stop lining up.
A script piped into grafana/k6 with `run -` fails on a relative import - why, and what fixes it?
basics
~20 sPiping delivers one file and nothing else. k6 records a stdin script as /-, so relative imports resolve against the container's working directory, not the script's folder. Mount the directory and pass an in-container path instead.
For a JS-fluent team, what does k6's script-as-a-JavaScript-module model make easy, and what does it cost?
basics
~20 sA k6 test is a JavaScript module: imports, an exported options object, a default function. It reviews, diffs and merges like application code. The cost is that authoring and review require JavaScript, and the runtime is not Node.
After four k6 instances each run one execution segment, what does core k6 not do for you?
basics
~10 sCore k6 divides the plan but never rejoins the results. There is no primary process, each instance evaluates its thresholds against only its own samples, and each writes its own output stream and summary.