K6 Load Testing
"Comprehensive k6 load testing skill for API, browser, and scalability testing. Write realistic load scenarios, analyze results, and integrate with CI/CD."
$ npx claude-code-templates@latest --skill="development/k6-load-testing" --yesRequires Claude Code. The command adds this skill to your project's .claudedirectory — nothing runs on ToolZip's servers.
What's inside this skill
Component source (preview)
k6 Load Testing
Overview
k6 is a modern, developer-centric load testing tool that helps you write and execute performance tests for HTTP APIs, WebSocket endpoints, and browser scenarios. This skill provides comprehensive guidance on writing realistic load tests, configuring test scenarios (smoke, load, stress, spike, soak), analyzing results, and integrating with CI/CD pipelines.
Use this skill when you need to validate system performance, identify bottlenecks, ensure SLA compliance, or catch performance regressions before deployment.
When to Use This Skill
- Use when you need to load test HTTP APIs, WebSocket endpoints, or browser scenarios
- Use when setting up performance regression tests in CI/CD
- Use when analyzing system behavior under various load conditions
- Use when comparing performance between code changes
- Use when validating SLA requirements and performance budgets
k6 Basics
Installation
# macOS
brew install k6
# Windows
choco install k6
# Linux
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
Quick Start
// simple-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
const res = http.get('https://httpbin.test.k6.io/get');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Run with: k6 run simple-test.js
Test Configuration
Common Options
export const options = {
// Virtual Users (concurrent users)
vus: 100,
// Test duration
duration: '5m',
// Or use stages for ramp-up/ramp-down
stages: [
{ duration: '30s', target: 20 }, // Ramp up
{ duration: '1m', target: 100 }, // Stay at 100
{ duration: '30s', target: 0 }, // Ramp down
],
// Thresholds (SLA)
thresholds: {
http_req_duration: ['p(95)<500'], // 95% requests < 500ms
http_req_failed: ['rate<0.01'], // Error rate < 1%
},
// Load zones (distributed testing)
ext: {
loadimpact: {
name: 'My Load Test',
distribution: {
'amazon:us:ashburn': { weight: 50 },
'amazon:eu: Dublin': { weight: 50 },
},
},
},
};
Test Types
| Type | Use Case | Configuration |
|---|---|---|
| Smoke Test | Verify basic functionality | Low VUs (1-5), short duration |
| Load Test | Normal expected load | Target VUs based on traffic |
| Stress Test | Find breaking point | Ramp beyond capacity |
| Spike Test | Sudden traffic spikes | Rapid increase/decrease |
| Soak Test | Long-term stability | Extended duration |
HTTP Testing
Basic Requests
import http from 'k6/http';
import { check, sleep } from 'k6';
export default function () {
// GET request
const getRes = http.get('https://api.example.com/users');
check(getRes, {
'GET succeeded': (r) => r.status === 200,
'has users': (r) => r.json('data.length') > 0,
});
// POST request with JSON body
const postRes = http.post('https://api.example.com/users',
JSON.stringify({ name: 'Test User', email: 'test@example.com' }),
{
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + __ENV.API_TOKEN,
},
}
);
check(postRes, {
'POST succeeded': (r) => r.status === 201,
'user created': (r) => r.json('id') !== undefined,
});
sleep(1);
}
Request Chaining
import http from 'k6/http';
import { check } from 'k6';
export default function () {
// Login and extract token
const loginRes = http.post('https://api.example.com/login',
JSON.stringify({ email: 'test@example.com', password: 'password123' })
);
const token = loginRes.json('access_token');
// Use token in subsequent requests
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
};
const profileRes = http.get('https://api.example.com/profile', {
headers: headers,
});
check(profileRes, {
'profile loaded': (r) => r.status === 200,
});
}
Parameterized Testing
import http from 'k6/http';
import { check } from 'k6';
const usernames = ['user1', 'user2', 'user3', 'user4', 'user5'];
export default function () {
// Use shared array with VU-specific index
const username = usernames[__VU % usernames.length];
const res = http.get(`https://api.example.com/users/${username}`);
check(res, {
'user found': (r) => r.status === 200,
});
}
Browser Testing (k6 Browser)
import { browser } from 'k6/browser';
export const options = {
scenarios: {
browser_test: {
executor: 'constant-vus',
vus: 5,
duration: '30s',
browser: {
type: 'chromium',
},
},
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto('https://example.com');
const title = await page.title();
console.log(`Page title: ${title}`);
// Click and interact
await page.click('button[data-testid="submit"]');
// Wait for response
await page.waitForSelector('.success-message');
} finally {
await page.close();
}
}
Install browser support: k6 install chromium
WebSocket Testing
import ws from 'k6/ws';
import { check } from 'k6';
export default function () {
const url = 'wss://echo.websocket.org';
ws.connect(url, {}, function (socket) {
socket.on('open', () => {
console.log('WebSocket connected');
socket.send('Hello WebSocket');
});
socket.on('message', (data) => {
console.log(`Received: ${data}`);
check(data, {
'echo received': (d) => d.includes('Hello'),
});
});
socket.on('close', () => {
console.log('WebSocket closed');
});
// Send periodic messages
socket.setInterval(function () {
socket.send('ping');
}, 1000);
// Close after 5 seconds
socket.setTimeout(function () {
socket.close();
}, 5000);
});
}
Data Handling
CSV Data Source
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
// Option 1: Load once, shared across VUs
const users = new SharedArray('users', function () {
return open('./users.csv').split('\n').slice(1).map(line => {
const [email, password] = line.split(',');
return { email, password };
});
});
export default function () {
const user = users[__VU % users.length];
const res = http.post('https://api.example.com/login',
JSON.stringify({ email: user.email, password: user.password })
);
check(res, { 'login successful': (r) => r.status === 200 });
}
JSON Data Source
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
const products = new SharedArray('products', function () {
return JSON.parse(open('./products.json'));
});
export default function () {
const product = products[Math.floor(Math.random() * products.length)];
const res = http.get(`https://api.example.com/products/${product.id}`);
check(res, { 'product found': (r) => r.status === 200 });
}
Thresholds & SLA
Basic Thresholds
export const options = {
vus: 50,
duration: '2m',
thresholds: {
// Response time thresholds
http_req_duration: ['p(95)<500', 'p(99)<1000'],
// Error rate threshold
http_req_failed: ['rate<0.01'],
// Throughput threshold
http_reqs: ['rate>100'],
},
};
Advanced Thresholds
export const options = {
thresholds: {
// Multiple thresholds on same metric
http_req_duration: [
'p(90)<300', // 90th percentile < 300ms
'p(95)<500', // 95th percentile < 500ms
'p(99)<1000', // 99th percentile < 1s
'avg<200', // average < 200ms
],
// Custom metrics
my_custom_metric: ['avg<100'],
// Abort on threshold failure
'http_req_duration{method:GET}': ['p(95)<300'],
},
};
Custom Metrics
Counters
import http from 'k6/http';
import { Counter, Trend, Rate, Gauge } from 'k6/metrics';
// Define custom metrics
const myCounter = new Counter('api_calls_total');
const responseTime = new Trend('response_time');
const errorRate = new Rate('error_rate');
const activeUsers = new Gauge('active_users');
export default function () {
const res = http.get('https://api.example.com/data');
// Increment counter
myCounter.add(1);
// Add to trend (for percentiles)
responseTime.add(res.timings.duration);
// Track error rate
errorRate.add(res.status !== 200);
// Set gauge value
activeUsers.add(__VU);
// Tagged metrics
const taggedRes = http.get('https://api.example.com/users', {
tags: { endpoint: 'users', env: 'prod' },
});
}
CI/CD Integration
GitHub Actions
# .github/workflows/load-test.yml
name: Load Tests
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Daily at 2 AM
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup k6
uses: grafana/k6-action@v0.2.0
- name: Run load test
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
run: k6 run --out json=results.json load-test.js
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: k6-results
path: results.json
- name: Check thresholds
if: failure()
run: |
echo "Load test failed thresholds!"
exit 1
GitLab CI
# .gitlab-ci.yml
load_test:
image: grafana/k6:latest
script:
- k6 run load-test.js
artifacts:
when: always
paths:
- results.json
reports:
junit: results.xml
Results Analysis
Built-in Reports
# Text summary
k6 run load-test.js
# JSON output for parsing
k6 run --out json=results.json load-test.js
# InfluxDB + Grafana
k6 run --out influxdb=http://localhost:8086/k6 load-test.js
# Prometheus remote write
k6 run --out prometheus=localhost:9090/k6 load-test.js
# Cloud results
k6 run --out cloud load-test.js
Interpreting Results
| Metric | Description | Good | Warning | Bad |
|---|---|---|---|---|
| http_req_duration (p95) | 95% response time | < 300ms | 300-500ms | > 500ms |
| http_req_failed | Error rate | < 0.1% | 0.1-1% | > 1% |
| http_reqs | Requests/sec | Meeting target | Near limit | At limit |
| vus | Virtual users | Stable | Gradual increase | Unexpected spike |
Examples
Example 1: Basic API Load Test
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50,
duration: '2m',
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('https://api.example.com/users');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
Example 2: Test with Authentication and Data Parameterization
```javascript
import http from 'k6/http';
import { check } from 'k6';
import { SharedArray } from 'k6/data';
const users = new SharedArray('users', function () {
return JSON.parse(o
Preview truncated. View the full source on GitHub →
Related Claude Code Skills
Code Reviewer
Comprehensive code review skill for TypeScript, JavaScript, Python, Swift, Kotlin, Go. Includes automated code analysis, best practice checking, security scanning, and review checklist generation. Use when reviewing pull requests, providing code feedback, identifying issues, or ensuring code quality standards.
Senior Frontend
Comprehensive frontend development skill for building modern, performant web applications using ReactJS, NextJS, TypeScript, Tailwind CSS. Includes component scaffolding, performance optimization, bundle analysis, and UI best practices. Use when developing frontend features, optimizing performance, implementing UI/UX designs, managing state, or reviewing frontend code.
Senior Backend
Comprehensive backend development skill for building scalable backend systems using NodeJS, Express, Go, Python, Postgres, GraphQL, REST APIs. Includes API scaffolding, database optimization, security implementation, and performance tuning. Use when designing APIs, optimizing database queries, implementing business logic, handling authentication/authorization, or reviewing backend code.
Senior Architect
Comprehensive software architecture skill for designing scalable, maintainable systems using ReactJS, NextJS, NodeJS, Express, React Native, Swift, Kotlin, Flutter, Postgres, GraphQL, Go, Python. Includes architecture diagram generation, system design patterns, tech stack decision frameworks, and dependency analysis. Use when designing system architecture, making technical decisions, creating architecture diagrams, evaluating trade-offs, or defining integration patterns.
Skill Creator
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
Senior Fullstack
Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.
Catalog data and component content are sourced from the open-source davila7/claude-code-templates project (MIT license). ToolZip curates the listing and writes original descriptions; every component links back to its original source. Claude Code is a product of Anthropic. ToolZip is an independent catalog and is not affiliated with or endorsed by Anthropic.