Skip to main content
The k6/execution module provides detailed information about the current test’s execution state, including scenario metadata, VU information, and test control functions.

Overview

Use this module to:
  • Access scenario and test metadata
  • Get unique identifiers for VUs and iterations
  • Control test execution (abort, fail)
  • Set custom tags and metadata on metrics
  • Retrieve consolidated test options

Importing the Module

import exec from 'k6/execution';

API Reference

The execution object provides four main property groups:

instance

Information about the current load generator instance (k6 process).
instance.iterationsInterrupted
number
Number of prematurely interrupted iterations in the current instance.
instance.iterationsCompleted
number
Number of completed iterations in the current instance.
instance.vusActive
number
Number of currently active VUs.
instance.vusInitialized
number
Number of currently initialized VUs.
instance.currentTestRunDuration
number
Time elapsed since the start of the current test run (milliseconds).

scenario

Metadata and execution details about the current running scenario.
scenario.name
string
The assigned name of the running scenario.
scenario.executor
string
The name of the running executor type (e.g., "shared-iterations", "ramping-vus").
scenario.startTime
number
Unix timestamp (milliseconds) when the scenario started.
scenario.progress
number
Scenario progress as a float between 0 and 1.
scenario.iterationInInstance
number
Unique zero-based sequential number of the current iteration in the scenario, across the current instance.
scenario.iterationInTest
number
Unique zero-based sequential number of the current iteration in the scenario, across all k6 instances (local, cloud, distributed).

test

Control functions and test-wide information.
test.abort([message])
function
Aborts the test run with exit code 108. Optionally provide an error message.Parameters:
message
string
Optional error message to log
Aborting does not prevent teardown() from running.
test.fail([message])
function
Marks the test run as failed with exit code 110. Does not interrupt test execution - all iterations finish normally.Parameters:
message
string
Optional failure message to log
test.options
object
Returns an object with all consolidated test options following the order of precedence. Properties where no option is defined return null.

vu

Metadata and execution details about the current VU.
vu.iterationInInstance
number
Iteration identifier for this VU in the current instance. Only unique for this VU and instance.
vu.iterationInScenario
number
Iteration identifier for this VU in the current scenario. Only unique for this VU and scenario.
vu.idInInstance
number
VU identifier across the instance. Not unique across multiple instances.
vu.idInTest
number
Globally unique VU identifier across the entire test run.
vu.metrics.tags
object
Map for controlling VU-level tags. Tags are included in every metric emitted by this VU and maintained across iterations.
vu.metrics.metadata
object
Map for controlling VU-level metadata. Metadata is included in every metric emitted by this VU and maintained across iterations.
Unique Identifiers: All unique identifiers are sequentially generated starting from zero (iterations) or one (VU IDs). In distributed/cloud tests, identifiers remain unique across instances, though gaps may exist due to different execution speeds.

Examples

Basic Scenario Information

import exec from 'k6/execution';

export const options = {
  scenarios: {
    myscenario: {
      executor: 'shared-iterations',
      maxDuration: '30m',
    },
  },
};

export default function () {
  console.log(exec.scenario.name); // "myscenario"
  console.log(exec.scenario.executor); // "shared-iterations"
  console.log(exec.scenario.progress); // 0.0 to 1.0
}

Getting Unique Data

Use iteration identifiers for data parameterization:
import { SharedArray } from 'k6/data';
import exec from 'k6/execution';
import http from 'k6/http';

const users = new SharedArray('users', () => {
  return JSON.parse(open('./users.json'));
});

export default function () {
  // Each iteration gets a unique user
  const user = users[exec.scenario.iterationInTest % users.length];
  
  http.post('https://test.k6.io/login', {
    username: user.username,
    password: user.password,
  });
}

Timing Operations

import exec from 'k6/execution';
import http from 'k6/http';

export default function () {
  // Measure time since scenario start
  const startTime = new Date(exec.scenario.startTime);
  const elapsed = new Date() - startTime;
  
  http.get('https://test.k6.io');
  console.log(`Step 1: scenario ran for ${elapsed}ms`);
  
  http.get('https://test.k6.io/news.php');
  const elapsed2 = new Date() - startTime;
  console.log(`Step 2: scenario ran for ${elapsed2}ms`);
}

Conditional Logic by Scenario

import exec from 'k6/execution';
import http from 'k6/http';

export const options = {
  scenarios: {
    'smoke-test': {
      executor: 'constant-vus',
      vus: 1,
      duration: '1m',
    },
    'load-test': {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '5m', target: 100 },
        { duration: '10m', target: 100 },
        { duration: '5m', target: 0 },
      ],
    },
  },
};

export default function () {
  if (exec.scenario.name === 'smoke-test') {
    // Run basic health checks
    http.get('https://test.k6.io/health');
  } else {
    // Run full user journey
    http.get('https://test.k6.io');
    http.post('https://test.k6.io/login', { /* ... */ });
    http.get('https://test.k6.io/dashboard');
  }
}

Test Abort

import exec from 'k6/execution';
import http from 'k6/http';

export default function () {
  const res = http.get('https://test.k6.io/health');
  
  // Abort test if health check fails
  if (res.status !== 200) {
    exec.test.abort('Health check failed - aborting test');
  }
  
  // Continue with test logic
  http.get('https://test.k6.io');
}

export function teardown() {
  console.log('Teardown still runs after test.abort()');
}

Test Fail

import http from 'k6/http';
import exec from 'k6/execution';

export const options = {
  iterations: 10,
};

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

  // Mark test as failed on iteration 3 but continue running
  if (exec.vu.iterationInInstance === 3) {
    exec.test.fail(`iteration ${exec.vu.iterationInInstance}: marked the test as failed`);
  }

  console.log(`iteration ${exec.vu.iterationInInstance} executed`);
}

Getting Test Options

import exec from 'k6/execution';

export const options = {
  stages: [
    { duration: '5s', target: 100 },
    { duration: '5s', target: 50 },
  ],
};

export default function () {
  console.log(exec.test.options.paused); // null
  console.log(exec.test.options.scenarios.default.stages[0].target); // 100
  console.log(exec.test.options.stages[1].target); // 50
}

Custom Tags

import http from 'k6/http';
import exec from 'k6/execution';

export default function () {
  // Set custom tags for this VU
  exec.vu.metrics.tags['mytag'] = 'value1';
  exec.vu.metrics.tags['mytag2'] = 2;
  exec.vu.metrics.tags['user_type'] = __VU % 2 === 0 ? 'premium' : 'free';

  // These HTTP requests will be tagged with mytag, mytag2, and user_type
  http.batch([
    'https://test.k6.io',
    'https://quickpizza.grafana.com'
  ]);
}
System Tag Override: Setting a tag with the same key as a system tag is allowed but requires caution. Most system tags (like url) won’t actually change their value for HTTP requests since they’re determined by the request itself. However, setting the name tag works as expected for URL grouping.

Custom Metadata

import http from 'k6/http';
import exec from 'k6/execution';

export default function () {
  // Set high-cardinality metadata (like trace IDs)
  exec.vu.metrics.metadata['trace_id'] = `trace-${Date.now()}-${__VU}`;
  exec.vu.metrics.metadata['user_id'] = `user-${exec.vu.idInTest}`;

  // Metrics from these requests include the metadata
  http.batch(['https://test.k6.io', 'https://quickpizza.grafana.com']);

  // Unset metadata
  delete exec.vu.metrics.metadata['trace_id'];
  
  // These requests won't have trace_id metadata
  http.batch(['https://test.k6.io', 'https://quickpizza.grafana.com']);
}

Unique Data Distribution

import { SharedArray } from 'k6/data';
import exec from 'k6/execution';
import http from 'k6/http';

const products = new SharedArray('products', () => {
  return JSON.parse(open('./products.json'));
});

export const options = {
  scenarios: {
    purchase: {
      executor: 'per-vu-iterations',
      vus: 10,
      iterations: 100,
    },
  },
};

export default function () {
  // Ensure each iteration tests a unique product
  const productIndex = exec.scenario.iterationInTest % products.length;
  const product = products[productIndex];
  
  http.post('https://api.example.com/purchase', {
    product_id: product.id,
    quantity: 1,
  });
  
  console.log(`VU ${exec.vu.idInTest}, Iteration ${exec.vu.iterationInScenario}: Purchased ${product.name}`);
}

Tag and Metadata Types

Supported Tag Types

k6 supports the following types as tag values:
  • Strings
  • Numbers
  • Booleans
All values are implicitly converted to strings. Objects and arrays are not allowed.
// Valid
exec.vu.metrics.tags['string_tag'] = 'value';
exec.vu.metrics.tags['number_tag'] = 42;
exec.vu.metrics.tags['bool_tag'] = true;

// Invalid (will warn or throw if 'throw' option is set)
exec.vu.metrics.tags['object_tag'] = { key: 'value' }; // ❌
exec.vu.metrics.tags['array_tag'] = [1, 2, 3]; // ❌

Tags vs Metadata

AspectTagsMetadata
CardinalityLow (for grouping/filtering)High (unique IDs, traces)
ThresholdsCan be usedCannot be used
FilteringStandard metric filteringOutput-specific handling
Use CaseEnvironment, test type, regionTrace IDs, user IDs, request IDs

Best Practices

Use exec.scenario.iterationInTest or exec.vu.idInTest to distribute unique data across all VUs and instances:
const user = users[exec.scenario.iterationInTest % users.length];
Be careful when setting custom tags that match system tag names. Most won’t behave as expected:
// ❌ Won't actually change the URL tag on http.get()
exec.vu.metrics.tags['url'] = 'custom';

// ✅ 'name' tag works for URL grouping
exec.vu.metrics.tags['name'] = 'api_call';
Use metadata instead of tags for high-cardinality data to avoid metric explosion:
// ✅ Good: High-cardinality data
exec.vu.metrics.metadata['trace_id'] = uniqueTraceId;

// ❌ Bad: Creates too many tag combinations
exec.vu.metrics.tags['trace_id'] = uniqueTraceId;
Always use teardown() for cleanup, as it runs even after test.abort():
export function teardown(data) {
  // Clean up test data, close connections, etc.
  // This runs even if test.abort() was called
}

Init Context

Global variables and initialization

Scenarios

Configure test scenarios

Tags and Groups

Organize and filter metrics

Test Lifecycle

Understanding k6 execution phases

Build docs developers (and LLMs) love