k6 Load Testing

Script Structure & Basic HTTP

import http from 'k6/http'; import { check, sleep } from 'k6'; // Options โ€” configure VUs and duration export const options = { vus: 10, // virtual users duration: '30s', // test duration }; // Default function runs per VU per iteration export default function () { const res = http.get('https://httpbin.org/get'); check(res, { 'status is 200': (r) => r.status === 200, 'response time < 500ms': (r) => r.timings.duration < 500, 'body contains json': (r) => r.headers['Content-Type'].includes('json'), }); sleep(1); // think time between iterations } // Run: k6 run script.js // Run with override: k6 run --vus 20 --duration 60s script.js

Stages โ€” Ramp Up / Down

export const options = { stages: [ { duration: '30s', target: 10 }, // ramp up to 10 VUs { duration: '1m', target: 10 }, // stay at 10 VUs { duration: '20s', target: 50 }, // spike to 50 VUs { duration: '1m', target: 50 }, // sustain spike { duration: '30s', target: 0 }, // ramp down to 0 ], }; // POST request with JSON body export default function () { const payload = JSON.stringify({ username: 'testuser', password: 'password123', }); const params = { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${__ENV.AUTH_TOKEN}`, }, timeout: '10s', }; const res = http.post('https://api.example.com/login', payload, params); check(res, { 'login succeeds': (r) => r.status === 200, 'token present': (r) => r.json('token') !== undefined, }); sleep(Math.random() * 2 + 1); // random think time 1-3s }

Thresholds โ€” Pass/Fail Criteria

export const options = { thresholds: { // HTTP error rate < 1% http_req_failed: ['rate<0.01'], // 95th percentile response time < 500ms http_req_duration: ['p(95)<500'], // 99th percentile < 1000ms 'http_req_duration{expected_response:true}': ['p(99)<1000'], // Custom metric threshold my_counter: ['count>1000'], // Threshold with abort http_req_failed: [{ threshold: 'rate<0.05', abortOnFail: true }], }, }; // k6 exits with non-zero if thresholds fail // Great for CI gates

Custom Metrics

import { Counter, Gauge, Rate, Trend } from 'k6/metrics'; const loginDuration = new Trend('login_duration'); const loginSuccessRate = new Rate('login_success_rate'); const activeUsers = new Gauge('active_users'); const totalRequests = new Counter('total_requests'); export default function () { const start = Date.now(); const res = http.post('/api/login', JSON.stringify({ user: 'alice' }), { headers: { 'Content-Type': 'application/json' }, }); loginDuration.add(Date.now() - start); loginSuccessRate.add(res.status === 200); totalRequests.add(1); activeUsers.add(1); sleep(1); activeUsers.add(-1); }

Scenarios

export const options = { scenarios: { // Constant VUs constant_load: { executor: 'constant-vus', vus: 20, duration: '2m', }, // Ramping VUs ramp_up: { executor: 'ramping-vus', stages: [ { duration: '30s', target: 20 }, { duration: '1m', target: 20 }, { duration: '30s', target: 0 }, ], }, // Constant arrival rate (RPS) constant_rps: { executor: 'constant-arrival-rate', rate: 100, // 100 requests per second timeUnit: '1s', duration: '2m', preAllocatedVUs: 50, }, // Shared iterations smoke_test: { executor: 'shared-iterations', vus: 5, iterations: 50, }, }, };

CLI Commands & Output

# Basic run k6 run script.js # With environment variables k6 run -e AUTH_TOKEN=abc123 script.js # Output to JSON k6 run --out json=results.json script.js # Output to InfluxDB k6 run --out influxdb=http://localhost:8086/k6 script.js # Output to Grafana Cloud k6 k6 run --out cloud script.js # Summary output k6 run --summary-export=summary.json script.js # Quiet mode (no progress bar) k6 run -q script.js # Built-in metrics output: # http_req_duration โ€” response time (min/avg/max/p90/p95) # http_req_failed โ€” error rate # http_reqs โ€” total requests # vus โ€” active virtual users # data_received โ€” bytes received