What it is
k6 is an open-source load testing tool that lets you write load tests in JavaScript and run them from the command line, designed for developers.
Installation
Linux (using package manager):
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install k6
# Fedora
sudo dnf install k6
Linux (downloading binary):
wget https://github.com/grafana/k6/releases/download/v0.40.0/k6-v0.40.0-linux_amd64.tar.gz
tar xvf k6-v0.40.0-linux_amd_64.tar.gz
sudo mv k6-v0.40.0-linux_amd64/k6 /usr/local/bin/
rm -rf k6-v0.40.0-linux_amd64*
macOS (using Homebrew):
brew install k6
Windows (using Chocolatey):
choco install k6
Windows (downloading binary):
# Download the latest release from https://k6.io/releases/
# Extract the k6.exe file to a directory in your PATH
Core Concepts
- VUs (Virtual Users): Represent concurrent users interacting with your application. k6 simulates these VUs executing your test script.
- Iterations: A single execution of the test script by a VU.
- Durations: The total time for which the load test should run.
- RPS (Requests Per Second): The target rate at which requests are sent to the target system.
- Checks: Assertions made within your script to verify the correctness of responses (e.g., status code, content).
- Thresholds: Conditions that, if not met during the test, will cause the test to fail (e.g., 99% of requests must complete in under 500ms).
- Metrics: Data points collected during the test (e.g., request duration, success rate, data sent/received). k6 collects standard metrics and allows custom metrics.
Commands / Usage
Running a Test Script:
k6 run --vus 10 --duration 30s ./my_test.js
Runs the my_test.js script with 10 virtual users for 30 seconds.
Running a Test with a Target RPS:
k6 run --vus 10 --iterations 1000 ./my_test.js
Runs the my_test.js script for 1000 total iterations, distributed among VUs. This is useful for controlling the total work done. To control rate, use --rps.
k6 run --vus 10 --rps 50 ./my_test.js
Runs the my_test.js script with 10 VUs, aiming for a total rate of 50 requests per second.
Running a Test with Thresholds:
k6 run --vus 10 --duration 1m --summary-trend-stats "avg,min,max,med,p(95),p(99)" --out json=results.json --outף html=report.html --outףinfluxdb=http://localhost:8086/k6 my_test.js
Runs the my_test.js script, outputs summary trend statistics, saves results to results.json, report.html, and sends data to InfluxDB.
Running Tests with Options from a File:
k6 run --config k6-config.json ./my_test.js
Runs the my_test.js script using configuration options defined in k6-config.json.
Running Tests with Environment Variables:
TARGET_URL=https://test.k6.io k6 run --vus 10 --duration 10s ./my_test.js
Sets the TARGET_URL environment variable to https://test.k6.io for use within the my_test.js script.
Running Tests with Stages (Ramping):
k6 run --stages '
[
{"duration": "30s", "target": 20},
{"duration": "1m", "target": 20},
{"duration": "10s", "target": 0}
]
' ./my_test.js
Runs the test with a gradual ramp-up to 20 VUs over 30 seconds, stays at 20 VUs for 1 minute, then ramps down to 0 VUs over 10 seconds.
Listing Available Options:
k6 run --help
Displays detailed help information for the run command and its flags.
Inspecting a Test Script:
k6 run --log-level debug --quiet --no-thresholds --no-checks ./my_test.js
Executes the script with debug logging, suppresses output unless there’s an error, and ignores thresholds and checks to see the raw script behavior.
Exporting k6 Results to Other Formats:
k6 run --out json=output.json ./my_test.js
k6 run --out html=report.html ./my_test.js
k6 run --out csv=output.csv ./my_test.js
k6 run --out datadog=api_key=YOUR_API_KEY,site=YOUR_SITE ./my_test.js
k6 run --out influxdb=http://localhost:8086/k6 ./my_test.js
Runs the test and exports results in JSON, HTML, CSV, Datadog, or InfluxDB format.
Running a Test in Distributed Mode (k6 Cloud):
k6 cloud ./my_test.js --token YOUR_CLOUD_TOKEN --project my-project --name "My Distributed Test"
Uploads and runs the my_test.js script on k6 Cloud, using your provided API token, project, and test name.
Managing k6 Extensions:
k6 extension build ./my_extension_dir
k6 extension init ./my_extension_dir
Builds or initializes a k6 extension.
Version Check:
k6 version
Displays the installed k6 version.
General Flags (apply to most commands)
--help: Show help for a command.--config <file>: Load configuration from a JSON file.--out <format>=<params>: Output results to a specific format (e.g.,json=results.json,html=report.html). Multiple--outflags can be used.--log-level <level>: Set the logging level (e.g.,debug,info,warn,error).--quiet: Suppress non-error output.--no-color: Disable colored output.--http-debug <filter>: Print HTTP request/response details (e.g.,full,headers,body).
run Command Specific Flags
--vus <number>: Number of virtual users.--duration <duration>: Duration of the test (e.g.,30s,5m).--iterations <number>: Total number of iterations to perform.--rps <number>: Target requests per second.--stages '<json_array>': Define stages for gradual load changes.--max-redirects <number>: Maximum number of HTTP redirects to follow.--insecure-skip-tls-verify: Skip TLS certificate verification (use with caution).--ssl-skip: Alias for--insecure-skip-tls-verify.--arkeit <file>: Path to a k6 ARKIT file for advanced configuration.--system <driver>: Specify the system driver for execution (e.g.,local).--no-usage-report: Disable sending anonymous usage data to k6.--no-thresholds: Do not fail the test if thresholds are not met.--no-checks: Do not fail the test if checks fail.--summary-trend-stats <stats>: Comma-separated list of trend statistics to display (e.g.,avg,min,max,med,p(95),p(99)).--summary-time-unit <unit>: Unit for time in summary output (e.g.,ms,s).--executor <executor>: Specify the VU code executor (e.g.,per-vu,shared-iterations,constant-vus,ramping-vus).--graceful-stop <duration>: Duration to wait for VUs to finish their current iteration before shutting down.--graceful-ramp-down <duration>: Duration to wait for VUs to finish their current iteration during a ramp-down.--env <key>=<value>: Set environment variables for the test script.
browser Command Specific Flags
--browser-ui: Enable browser UI for visual feedback.--browser-timeout <duration>: Timeout for browser actions.--browser-executable-path <path>: Path to the browser executable.
k6 browser ./my_browser_test.js
Runs a browser-based test script.
Common Patterns
Load Testing an API Endpoint:
# my_api_test.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 20,
duration: '1m',
};
export default function () {
http.get('https://api.example.com/users');
sleep(1);
}
Run with:
k6 run ./my_api_test.js
Ramping Up Users and Checking Response Times:
# my_ramp_test.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 50 }, // ramp up to 50 users over 1 minute
{ duration: '2m', target: 50 }, // stay at 50 users for 2 minutes
{ duration: '30s', target: 0 }, // ramp down to 0 users over 30 seconds
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests should be below 500ms
http_req_failed: ['rate<0.01'], // error rate should be less than 1%
},
};
export default function () {
http.get('https://ecommerce.example.com/products');
sleep(Math.random() * 2); // Random sleep between 0 and 2 seconds
}
Run with:
k6 run --out html=report.html ./my_ramp_test.js
Testing a Login Flow with Custom Metrics:
# my_login_test.js
import http from 'k6/http';
import { sleep, check, fail } from 'k6';
import { Counter, Rate, Trend } from 'k6/metrics';
const loginFailures = new Counter('login_failures');
const loginDuration = new Trend('login_duration');
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
const payload = JSON.stringify({
username: 'testuser',
password: 'password123',
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};
const res = http.post('https://auth.example.com/login', payload, params);
const isSuccess = check(res, {
'login status is 200': (r) => r.status === 200,
'response body contains token': (r) => r.body.includes('token'),
});
if (!isSuccess) {
loginFailures.add(1);
// Optionally fail the test immediately if critical
// fail('Login failed or token not found');
} else {
loginDuration.add(res.timings.duration);
}
sleep(1);
}
Run with:
k6 run --out influxdb=http://localhost:8086/k6 ./my_login_test.js
Parameterized Tests using Environment Variables:
# my_param_test.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 5,
duration: '15s',
};
export default function () {
const targetUrl = __ENV.TARGET_URL || 'https://default.example.com';
http.get(`${targetUrl}/health`);
sleep(1);
}
Run with:
TARGET_URL=https://api.prod.example.com k6 run ./my_param_test.js
Using shared-iterations Executor for Fixed Number of Total Iterations:
# my_fixed_iterations_test.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
iterations: 1000,
vus: 10,
// executor defaults to 'per-vu' which means each VU runs iterations until total is met.
// 'shared-iterations' is useful when you want to ensure a fixed total number of requests regardless of VU speed.
// executor: 'shared-iterations',
};
export default function () {
http.get('https://service.example.com/status');
sleep(0.5);
}
Run with:
k6 run ./my_fixed_iterations_test.js
Running Tests with Different Executors:
# Constant VUs (default if not specified)
k6 run --executor constant-vus --vus 10 --duration 1m ./my_test.js
# Ramping VUs
k6 run --executor ramping-vus --stages '[{"duration": "1m", "target": 50}]' ./my_test.js
# Shared Iterations
k6 run --executor shared-iterations --iterations 1000 --vus 10 ./my_test.js
# Per-VU Iterations (default)
k6 run --executor per-vu --iterations 100 --vus 10 ./my_test.js
Gotchas
sleep()is Crucial: Withoutsleep(), VUs will run as fast as possible, potentially overwhelming your system and skewing results. Usesleep(1)orsleep(Math.random() * N)to simulate realistic user think times.http_req_failedis a Rate: The default thresholdhttp_req_failed: ['rate<0.01']means less than 1% of requests should fail. It’s a rate, not a count.- Thresholds vs. Checks: Checks assert conditions within a single iteration and report pass/fail. Thresholds are global conditions evaluated over the entire test run and determine the test’s exit code. A test can pass locally but fail the CI/CD pipeline if thresholds are not met.
--durationvs.--iterations:--durationspecifies how long the test runs.--iterationsspecifies the total number of iterations to complete. If the VUs can’t complete all iterations within the duration, the test will stop at the duration.--rpsis a Target: The--rpsflag aims for a specific rate, but the actual achieved RPS can be lower due to network latency, server response times, or the number of VUs not being sufficient to generate that rate.- Environment Variables in Scripts: Access environment variables using
__ENV.VARIABLE_NAME. These are injected into the k6 process. - Browser Testing Limitations: Browser tests are significantly more resource-intensive than protocol-level tests. Running many browser VUs concurrently requires substantial local resources or k6 Cloud.
- Default VU Executor: If not specified,
k6 rundefaults to theper-vuexecutor. This means each VU will run iterations until the totaliterationscount is met or thedurationis reached. For specific control over iteration distribution, useshared-iterationsorramping-vus. - Graceful Shutdown: When stopping a test (e.g., by pressing Ctrl+C or reaching the end of a duration), k6 attempts a graceful shutdown. The
--graceful-stopflag allows you to configure how long k6 waits for VUs to finish their current iteration before forcibly terminating them. This is important for ensuring that all in-flight requests have a chance to complete.