Skip to main content
Every k6 test executes through distinct lifecycle stages in a specific order. Understanding this lifecycle helps you structure your tests correctly and avoid common mistakes.

The four lifecycle stages

A k6 test always runs through these stages in order:
1

Init context

Prepare the script by loading files, importing modules, and defining lifecycle functions. Runs once per VU.
2

Setup (optional)

Set up the test environment and generate data to share across VUs. Runs once at test start.
3

VU execution

Run the main test function repeatedly for the configured duration or iterations. Each VU runs independently.
4

Teardown (optional)

Clean up the test environment and process results. Runs once at test end.

Lifecycle overview

Basic structure

Here’s the basic structure showing all lifecycle stages:

Init context

The init stage is required and runs before the test begins. Code in the init context executes once per VU to initialize the test conditions. All code outside of lifecycle functions is init code and executes first.

What belongs in init

Init context restrictions

Init code cannot make HTTP requests. This ensures the init stage is reproducible across test runs, since HTTP responses are dynamic and unpredictable.
Init code separates setup from execution, which improves k6 performance and makes test results more reliable.

VU execution stage

The VU stage is required and contains the actual test workload. Scripts must define at least one scenario function (typically default) that runs repeatedly.

The default function

The most common pattern uses the default function:
VU code runs continuously throughout the test duration. Each VU executes the function from start to end, then immediately loops back to the start.

VU execution lifecycle

1

Execute function

The VU runs the function from start to finish
2

Reset VU state

k6 clears cookies and may close TCP connections (depending on options)
3

Loop back

The VU immediately starts executing the function again
This continues until the test duration expires or iteration limit is reached.

What VU code can and cannot do

VU code CAN

  • Make HTTP requests
  • Emit metrics
  • Run checks
  • Use imported modules

VU code CANNOT

  • Load files from filesystem
  • Import new modules
  • Define new metrics

Setup and teardown

The setup and teardown functions are optional lifecycle functions that run once per test.

Setup function

Setup runs once at the beginning of the test, after init but before VU execution:
Unlike init code, setup functions can make HTTP requests since they run during test execution.

Teardown function

Teardown runs once at the end of the test, after all VU execution completes:
If the setup() function throws an error, teardown() will not run. Add error handling to setup to ensure proper cleanup.

Sharing data between stages

The setup() function can return data that gets passed to both default() and teardown():

Data sharing rules

  • You can only pass data (JSON) between stages, not functions
  • Each VU receives an independent copy of the data
  • VUs cannot modify the shared data
  • Large data increases memory consumption

Skipping setup and teardown

You can skip these stages using CLI flags:
This is useful when iterating on VU code without repeatedly running setup/teardown logic.

Scenario functions

Instead of the default function, you can define custom scenario functions:
This allows different scenarios to execute different functions with different workload patterns.

Complete example

Here’s a complete test using all lifecycle stages:

Best practices

Minimize init code

Keep init code lightweight. Heavy computation in init slows test startup.

Use setup for dynamic data

Generate test data in setup() and share it across VUs.

Keep VU code focused

VU code should only contain the workload you want to measure.

Handle setup errors

Add error handling to setup() to ensure teardown() runs.