Skip to main content
Metrics are the heart of k6 performance testing. k6 automatically collects built-in metrics and allows you to define custom metrics for your specific testing needs.

Metric Types

k6 supports four metric types, defined in metrics/metric_type.go:

Counter

A metric that sums all added values. From metrics/metric_type.go:
import { Counter } from 'k6/metrics';

const myCounter = new Counter('my_counter');

export default function() {
  myCounter.add(1);  // Increment by 1
  myCounter.add(5);  // Increment by 5
  // Total: 6
}
Aggregation methods: count, rate

Gauge

A metric that stores the latest value. From metrics/metric_type.go:
import { Gauge } from 'k6/metrics';

const myGauge = new Gauge('my_gauge');

let maxResponseTime = 0.0;

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  maxResponseTime = Math.max(maxResponseTime, res.timings.duration);
  myGauge.add(maxResponseTime);  // Store current max
}
Aggregation methods: value

Trend

A metric that tracks all values and calculates statistics. From metrics/metric_type.go:
import { Trend } from 'k6/metrics';

const myTrend = new Trend('my_trend');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  // Track connection + TLS time
  myTrend.add(res.timings.connecting + res.timings.tls_handshaking);
}
Aggregation methods: avg, min, max, med, p(N) (percentiles)

Rate

A metric that tracks the percentage of non-zero values. From metrics/metric_type.go:
import { Rate } from 'k6/metrics';
import { check } from 'k6';

const myRate = new Rate('my_rate');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  const passed = check(res, { 'status is 200': (r) => r.status === 200 });
  
  myRate.add(passed);  // Add true (1) or false (0)
  // Rate calculates: (number of trues) / (total samples)
}
Aggregation methods: rate

Built-in Metrics

k6 automatically collects comprehensive metrics defined in metrics/builtin.go:

HTTP Metrics

From metrics/builtin.go, HTTP-related metrics:

http_reqs

Type: Counter
Description: Total number of HTTP requests

http_req_failed

Type: Rate
Description: Rate of failed requests (status >= 400 or network error)
export const options = {
  thresholds: {
    http_req_failed: ['rate<0.01'], // Less than 1% failures
  },
};

http_req_duration

Type: Trend (Time)
Description: Total request time (sending + waiting + receiving)
export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% under 500ms
  },
};

http_req_blocked

Type: Trend (Time)
Description: Time blocked before initiating request (waiting for free TCP connection)

http_req_connecting

Type: Trend (Time)
Description: Time spent establishing TCP connection

http_req_tls_handshaking

Type: Trend (Time)
Description: Time spent in TLS handshake

http_req_sending

Type: Trend (Time)
Description: Time spent sending request data

http_req_waiting

Type: Trend (Time)
Description: Time spent waiting for response (TTFB - Time To First Byte)

http_req_receiving

Type: Trend (Time)
Description: Time spent receiving response data

VU and Iteration Metrics

vus

Type: Gauge
Description: Current number of active virtual users

vus_max

Type: Gauge
Description: Maximum number of VUs initialized

iterations

Type: Counter
Description: Total number of completed iterations

iteration_duration

Type: Trend (Time)
Description: Time to complete one full iteration

dropped_iterations

Type: Counter
Description: Iterations that couldn’t start due to time constraints

Check Metrics

checks

Type: Rate
Description: Success rate of checks
import { check } from 'k6';

export const options = {
  thresholds: {
    checks: ['rate>0.95'], // 95% of checks must pass
  },
};

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  check(res, {
    'status is 200': (r) => r.status === 200,
  });
}

Group Metrics

group_duration

Type: Trend (Time)
Description: Time spent inside a group
import { group } from 'k6';

export default function() {
  group('user flow', function() {
    http.get('https://quickpizza.grafana.com/');
    http.get('https://quickpizza.grafana.com/api/pizza');
  });
}

WebSocket Metrics

From metrics/builtin.go, WebSocket-specific metrics:
  • ws_sessions (Counter) - Total WebSocket sessions
  • ws_msgs_sent (Counter) - Messages sent
  • ws_msgs_received (Counter) - Messages received
  • ws_ping (Trend, Time) - Ping duration
  • ws_session_duration (Trend, Time) - Session duration
  • ws_connecting (Trend, Time) - Connection time

gRPC Metrics

grpc_req_duration

Type: Trend (Time)
Description: gRPC request duration

Network Metrics

data_sent

Type: Counter (Data)
Description: Amount of data sent (bytes)

data_received

Type: Counter (Data)
Description: Amount of data received (bytes)

Custom Metrics

Create custom metrics to track application-specific data. From examples/custom_metrics.js:
import http from 'k6/http';
import { Counter, Gauge, Rate, Trend } from 'k6/metrics';
import { check } from 'k6';

// Define custom metrics in init context
const myCounter = new Counter('my_counter');
const myGauge = new Gauge('my_gauge');
const myRate = new Rate('my_rate');
const myTrend = new Trend('my_trend');

let maxResponseTime = 0.0;

export default function () {
  const res = http.get('https://quickpizza.grafana.com/');
  const passed = check(res, { 'status is 200': (r) => r.status === 200 });

  // Add one for number of requests
  myCounter.add(1);

  // Set max response time seen
  maxResponseTime = Math.max(maxResponseTime, res.timings.duration);
  myGauge.add(maxResponseTime);

  // Add check success or failure to keep track of rate
  myRate.add(passed);

  // Keep track of TCP-connecting and TLS handshaking part of response time
  myTrend.add(res.timings.connecting + res.timings.tls_handshaking);
}

Metric Tags

From metrics/tags.go, metrics can be filtered using tags:

System Tags

Automatic tags from metrics/system_tag.go:
  • method - HTTP method
  • status - HTTP status code
  • url - Request URL
  • name - Request name
  • group - Group name
  • check - Check name
  • scenario - Scenario name
  • service - Service name (for gRPC)

Custom Tags

Add custom tags to requests:
import http from 'k6/http';

export default function() {
  // Tag individual requests
  http.get('https://quickpizza.grafana.com/api/pizza', {
    tags: { my_tag: 'pizza_api' },
  });
  
  // Filter metrics by tag in thresholds
}

export const options = {
  thresholds: {
    'http_req_duration{my_tag:pizza_api}': ['p(95)<200'],
  },
};

Global Tags

Apply tags to all metrics:
export const options = {
  tags: {
    environment: 'production',
    team: 'backend',
  },
};

Metric Output

End-of-Test Summary

k6 displays metric statistics at test completion:
     ✓ status is 200

     checks.........................: 100.00% ✓ 150      ✗ 0   
     data_received..................: 4.5 MB  75 kB/s
     data_sent......................: 13 kB   217 B/s
     http_req_blocked...............: avg=1.5ms    min=1µs     med=5µs     max=145ms   p(95)=7µs   
     http_req_connecting............: avg=516µs    min=0s      med=0s      max=48ms    p(95)=0s    
     http_req_duration..............: avg=123ms    min=101ms   med=115ms   max=245ms   p(95)=187ms 
     http_req_failed................: 0.00%   ✓ 0        ✗ 150 
     http_req_receiving.............: avg=128µs    min=22µs    med=85µs    max=1.5ms   p(95)=294µs 
     http_req_sending...............: avg=34µs     min=7µs     med=24µs    max=208µs   p(95)=80µs  
     http_req_tls_handshaking.......: avg=0s       min=0s      med=0s      max=0s      p(95)=0s    
     http_req_waiting...............: avg=122ms    min=101ms   med=115ms   max=244ms   p(95)=186ms 
     http_reqs......................: 150     2.5/s
     iteration_duration.............: avg=1.12s    min=1.1s    med=1.11s   max=1.24s   p(95)=1.18s 
     iterations.....................: 150     2.5/s
     vus............................: 3       min=3      max=3 
     vus_max........................: 3       min=3      max=3

Metric Value Types

From metrics/value_type.go, metrics can represent:
  • Default - Generic numeric values
  • Time - Duration values (milliseconds)
  • Data - Data size values (bytes)
import { Trend } from 'k6/metrics';

// Time metric
const responseTime = new Trend('response_time', true);

// Default metric
const itemCount = new Trend('item_count');

Advanced Metric Patterns

Tracking Business Metrics

import { Counter, Trend } from 'k6/metrics';

const ordersCreated = new Counter('orders_created');
const orderValue = new Trend('order_value');

export default function() {
  const res = http.post('https://api.example.com/orders', JSON.stringify({
    items: ['pizza', 'soda'],
    total: 25.50,
  }));
  
  if (res.status === 201) {
    ordersCreated.add(1);
    orderValue.add(25.50);
  }
}

Tracking Error Types

import { Counter } from 'k6/metrics';

const errors4xx = new Counter('errors_4xx');
const errors5xx = new Counter('errors_5xx');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/api/pizza');
  
  if (res.status >= 400 && res.status < 500) {
    errors4xx.add(1);
  } else if (res.status >= 500) {
    errors5xx.add(1);
  }
}

Conditional Metrics

import { Trend } from 'k6/metrics';

const fastRequests = new Trend('fast_requests');
const slowRequests = new Trend('slow_requests');

export default function() {
  const res = http.get('https://quickpizza.grafana.com/');
  
  if (res.timings.duration < 200) {
    fastRequests.add(res.timings.duration);
  } else {
    slowRequests.add(res.timings.duration);
  }
}

Best Practices

1

Use Built-in Metrics First

Built-in metrics cover most use cases. Only add custom metrics when necessary.
2

Choose the Right Metric Type

Use Counter for totals, Gauge for latest values, Trend for statistics, and Rate for success rates.
3

Add Meaningful Tags

Tag metrics to enable filtering and detailed analysis.
4

Combine Metrics with Thresholds

Use metrics with thresholds to define pass/fail criteria.
Custom metrics are defined in the init context but recorded in the default function.
Too many custom metrics can impact test performance and increase memory usage.
Metrics provide the quantitative data you need to understand system performance and make informed decisions about scalability and reliability.

Build docs developers (and LLMs) love