Skip to main content
Every k6 test follows a structured lifecycle with four distinct phases. Understanding these phases is essential for writing effective load tests.

Test Lifecycle Phases

k6 executes tests in the following order:
1

Init Phase

Code in the init context runs once per VU at the beginning of the test.
2

Setup Phase

The setup() function runs once before the test starts.
3

VU Phase (Default Function)

The default function executes repeatedly for each VU iteration.
4

Teardown Phase

The teardown() function runs once after the test completes.

Init Context

The init context is where k6 prepares your test script. Code at the top level of your script runs during initialization.

What Happens in Init

Based on the k6 source code in internal/js/bundle.go, the init context:
  • Imports modules
  • Defines the default function and options
  • Creates custom metrics
  • Loads local files
  • Initializes module-provided types
The init context runs once per VU. With 10 VUs, init code executes 10 times total.
Do not make HTTP requests in the init context. They won’t be measured and will slow down test startup.

Setup Phase

The optional setup() function runs once before the test begins, regardless of VU count.

Setup Use Cases

  • Authenticate and obtain tokens
  • Prepare test data
  • Configure the system under test
  • Retrieve configuration values
Setup data is serialized to JSON and distributed to all VUs. Keep it lightweight.

Default Function (VU Phase)

The default function is the heart of your test. Each VU executes it repeatedly for the duration of the test.

Iteration Behavior

From the execution state implementation in lib/execution.go:
  • Each VU is tracked with counters for full and interrupted iterations
  • fullIterationsCount increments when iterations complete normally
  • interruptedIterationsCount increments when iterations are cut short
  • The activeVUs counter tracks currently executing VUs
An iteration is the complete execution of the default function, from start to finish.

Teardown Phase

The optional teardown() function runs once after all VUs finish executing.

Teardown Use Cases

  • Clean up test data
  • Log out or revoke tokens
  • Reset system state
  • Perform final validation
If the test is aborted (Ctrl+C), teardown may not execute. Design your tests to handle incomplete cleanup.

Execution Flow Diagram

Execution Status

k6 tracks test execution through multiple states defined in lib/execution.go:
  • ExecutionStatusCreated - Test created
  • ExecutionStatusInitVUs - Initializing VUs
  • ExecutionStatusInitExecutors - Initializing executors
  • ExecutionStatusInitDone - Initialization complete
  • ExecutionStatusSetup - Running setup
  • ExecutionStatusRunning - Default function executing
  • ExecutionStatusTeardown - Running teardown
  • ExecutionStatusEnded - Test complete

Best Practices

1

Keep Init Lightweight

Avoid expensive operations in init. Use it for imports and metric definitions only.
2

Use Setup for Authentication

Obtain tokens once in setup and distribute to VUs, rather than authenticating in every iteration.
3

Make Default Function Repeatable

Ensure the default function can run many times without side effects.
4

Handle Teardown Failures

Don’t rely on teardown for critical cleanup - it may not run if the test is interrupted.

Complete Example

Understanding the test lifecycle helps you structure tests efficiently and avoid common pitfalls like making unnecessary requests or reinitializing data in every iteration.