What are k6's setupTimeout and teardownTimeout defaults, and what happens when one expires?
answer
- both stages get a budget
- the same default for each
- sixty seconds unless you say otherwise
- two adjacent exit codes
- 100 for setup, 101 for teardown
basics
~20 sBoth default to 60 seconds in k6 v2. Overrunning setupTimeout fails the run with exit code 100 before any virtual user starts; overrunning teardownTimeout fails it with exit code 101 after the VU work is already done.
solid answer
~40 sk6 gives each stage a deadline: `setupTimeout` for `setup()` and `teardownTimeout` for `teardown()`, both defaulting to `60s`. On overrun k6 reports `setup() execution timed out after 60 seconds`, hints that you can raise the matching option, and exits **100** for setup or **101** for teardown. The difference matters: a setup timeout means no VU ever started and you have no results, while a teardown timeout means the load already ran and only the cleanup was cut short. Both are set in the exported `options` object or through `K6_SETUP_TIMEOUT` and `K6_TEARDOWN_TIMEOUT`; neither has a CLI flag, and `setupTimeout` must be a positive duration.
code
javascript · 14 linesexport const options = {
vus: 50,
duration: '5m',
setupTimeout: '3m',
teardownTimeout: '90s',
};
export function setup() {
return { token: 'minted-during-a-slow-cold-start' };
}
export default function (data) {
// ... uses data.token ...
}go deeper
Know that k6 gives setup() and teardown() 60 seconds each by default and that you raise the limit with the setupTimeout and teardownTimeout options.
Explain the two exit codes, 100 and 101, and why they differ: one means no VU ever ran, the other means the load finished and only cleanup was cut short.
Use the code to triage. Exit 100 in CI points at a cold or unavailable dependency in setup, and raising the deadline only helps when the wait is genuinely finite.
Decide what the team standardises: how much work is allowed inside a 60-second window at all, and which provisioning is moved out of the run entirely.
## Two deadlines, one default k6 wraps `setup()` and `teardown()` in a deadline so a hung lifecycle function cannot pin a run open forever. There is one option per stage: - **`setupTimeout`** — how long `setup()` may take. Default `60s`. - **`teardownTimeout`** — how long `teardown()` may take. Default `60s`. Both accept a duration string such as `'90s'` or `'3m'`. `setupTimeout` is validated to be positive, so `setupTimeout: '0s'` is rejected as bad configuration rather than treated as "no limit". There is no way to switch the deadline off; if a stage genuinely needs longer, you raise the number. The related `handleSummaryTimeout` covers the end-of-test summary hook and defaults to `120s`, so do not assume every k6 lifecycle deadline is a minute. ## What an expiry costs you | Stage | Option | Default | Exit code | State of the run | |---|---|---|---|---| | `setup()` | `setupTimeout` | `60s` | **100** | no VU started, no results, `teardown()` never called | | `teardown()` | `teardownTimeout` | `60s` | **101** | all VU work already done, cleanup cut short | k6's message names the stage and the elapsed budget — `setup() execution timed out after 60 seconds` — and attaches a hint pointing at the option to raise. Both codes are distinct from the ones a run is more often stopped by: **99** is a breached threshold and **104** is invalid configuration. Reading the code straight off the CI job tells you which stage died without opening a log. The asymmetry is what to reason about in an incident: - **Exit 100 is a failed run.** Nothing was measured. Whatever `setup()` was doing — logging in, seeding a fixture, waiting for a dependency to come up — never finished, so there is nothing to salvage and nothing to clean up. - **Exit 101 is a completed run with a dirty tail.** The metrics are real; what did not finish is the cleanup. Assume the environment still holds whatever `setup()` created and deal with it out of band. ## Where you set them They are ordinary k6 options, and they follow the usual precedence — an environment variable beats the in-script value: - in the exported `options` object: `setupTimeout: '3m'`; - as environment variables: `K6_SETUP_TIMEOUT=180s`, `K6_TEARDOWN_TIMEOUT=90s`; - in a JSON config file passed with `--config`. There is **no `--setup-timeout` flag**. This trips people up because `--no-setup` and `--no-teardown` do exist as flags, so the family looks like it should be complete. It is not: the booleans have flags, the durations do not. Note also that `-e` / `--env` is a different mechanism — it injects variables into `__ENV` for your script to read, and does not set k6 options. ## Why the setup deadline bites hardest The default 60 seconds is generous for a single login and tight for almost anything else. Realistic ways to overrun it: 1. **A cold dependency.** The target service scales from zero, and the first request in `setup()` waits out a container start. 2. **Serial work in a loop.** Minting one token is quick; minting one per tenant, one request at a time, is not. 3. **A dependency that is down.** `setup()` blocks on a connection that will never open, and the deadline is the only thing that ends the run. Raising the number is the right answer for case 1 and the wrong answer for case 3, where a longer deadline just delays the same failure. It is also worth remembering that Grafana Cloud k6 caps `setupTimeout` at 10 minutes, so a locally passing script with a five-minute setup is not automatically portable upward. ## Practical guidance - Set the number from measurement, not habit: time `setup()` once, then leave real headroom above it. - Keep `setup()` doing one thing. Bulk provisioning belongs outside the test run, not inside a 60-second window. - Treat exit **100** and exit **101** as different alerts in CI. One means you have no data; the other means you have data plus residue to clean up. - Fail fast inside `setup()` rather than letting the deadline do it. An explicit reachability check that throws with a clear message costs a second and tells you far more than `setup() execution timed out after 60 seconds` does. - Remember that the deadline covers the **whole** function, awaits included. An `async setup()` that awaits three sequential requests spends all three of their latencies against one budget. ## How the deadline is applied k6 wraps each call in a deadline before it enters the function and cancels the JavaScript runtime when the deadline passes. Two details follow from that: - The error k6 reports names the stage and the budget it was given, so the message always tells you which of the two options to raise. - Cancellation interrupts the running script rather than waiting politely for it. Work already in flight — an HTTP request, a write to a fixture store — is abandoned mid-way, which is another reason bulk provisioning inside `setup()` is a poor idea: a timeout can leave the target half-seeded with nothing to clean it up, because `teardown()` will not run either. The `noSetup` and `noTeardown` booleans are a separate lever from these durations: they decide **whether** the stage runs, while the timeouts decide **how long** it may take once it does.
- Is there a CLI flag for k6's setupTimeout?No. The duration options are settable only in the exported `options` object, through `K6_SETUP_TIMEOUT` / `K6_TEARDOWN_TIMEOUT`, or in a `--config` JSON file. The boolean pair `--no-setup` and `--no-teardown` does have flags, which is why the family looks more complete than it is.
- If teardown() times out, are the run's metrics still valid?Yes. Exit 101 happens after every executor has finished, so the load and its measurements already completed. What was cut short is the cleanup, so treat the target environment as still holding whatever setup created.
saying these in an interview costs you the question
- Thinks setupTimeout defaults to the whole test duration
- Says a stage timeout produces the same exit code as a failed threshold
- Looks for a --setup-timeout command-line flag
- Assumes a teardown timeout invalidates the run's metrics
- Sets setupTimeout to zero expecting it to mean unlimited