Write your first test
k6 tests are written using JavaScript, making them accessible to developers and easy to integrate into existing projects. In this guide, you’ll learn the basic structure of a k6 test and create your first load test script.
Prerequisites
Before you start:
Basic JavaScript knowledge : Familiarity with JavaScript or TypeScript syntax
k6 installed : Follow the installation guide if you haven’t already
Code editor : VS Code, JetBrains, or any text editor
If you’re unfamiliar with JavaScript, check out k6 Studio to generate tests without writing code.
Basic structure of a k6 test
Every k6 script follows a common structure with these core components:
Imports
Import k6 modules or JavaScript libraries to extend functionality: import http from 'k6/http' ;
import { sleep , check } from 'k6' ;
Options (optional)
Configure test execution settings like virtual users and duration: export const options = {
vus: 10 ,
duration: '30s' ,
};
Default function
The main test logic that k6 executes repeatedly: export default function () {
// Your test code here
}
Lifecycle functions (optional)
Code that runs before or after the test: export function setup () {
// Runs once before the test
}
export function teardown ( data ) {
// Runs once after the test
}
Create your first test
Let’s create a simple test that makes 10 HTTP GET requests with a 1-second delay between requests.
Create a test file
Create a new file named my-first-test.js: Or use k6’s built-in command to generate a template:
Import k6 modules
Add imports at the top of your file: // Import the http module to make HTTP requests
import http from 'k6/http' ;
// Import the sleep function to introduce delays
import { sleep } from 'k6' ;
Configure test options
Define how many times the test should run: import http from 'k6/http' ;
import { sleep } from 'k6' ;
export const options = {
// Execute the default function 10 times
iterations: 10 ,
};
Write the default function
Add the main test logic: import http from 'k6/http' ;
import { sleep } from 'k6' ;
export const options = {
iterations: 10 ,
};
// The default function runs repeatedly for the configured iterations
export default function () {
// Make a GET request to the target URL
http . get ( 'https://quickpizza.grafana.com' );
// Sleep for 1 second to simulate real-world usage
sleep ( 1 );
}
Run your test
Execute the test from your terminal: You’ll see output showing the test progress and results.
Add checks and validations
Checks allow you to validate responses and track success rates. They don’t stop test execution but provide pass/fail statistics.
import http from 'k6/http' ;
import { check , sleep } from 'k6' ;
export const options = {
iterations: 10 ,
};
export default function () {
const res = http . get ( 'https://quickpizza.grafana.com' );
// Validate the response
check ( res , {
'status is 200' : ( r ) => r . status === 200 ,
'response time < 500ms' : ( r ) => r . timings . duration < 500 ,
'body contains text' : ( r ) => r . body . includes ( 'pizza' ),
});
sleep ( 1 );
}
Checks are reported in the test summary and show the percentage of passing validations.
Run tests with virtual users
Instead of iterations, you can configure tests to run with multiple virtual users (VUs) for a specified duration.
Using command-line options
k6 run --vus 10 --duration 30s my-first-test.js
This runs the test with 10 virtual users for 30 seconds.
Using script options
import http from 'k6/http' ;
import { sleep } from 'k6' ;
export const options = {
vus: 10 , // 10 virtual users
duration: '30s' , // Run for 30 seconds
};
export default function () {
http . get ( 'https://quickpizza.grafana.com' );
sleep ( 1 );
}
Each virtual user runs the default function in a loop for the specified duration. This simulates concurrent users accessing your application.
Ramp up traffic with stages
For more realistic traffic patterns, gradually increase and decrease the number of virtual users:
import http from 'k6/http' ;
import { check , sleep } from 'k6' ;
export const options = {
stages: [
{ duration: '30s' , target: 20 }, // Ramp up to 20 VUs over 30s
{ duration: '1m30s' , target: 10 }, // Ramp down to 10 VUs
{ duration: '20s' , target: 0 }, // Ramp down to 0 VUs
],
};
export default function () {
const res = http . get ( 'https://quickpizza.grafana.com/' );
check ( res , { 'status is 200' : ( r ) => r . status === 200 });
sleep ( 1 );
}
This creates a more realistic load pattern that gradually increases, maintains, and decreases traffic.
Understanding the init context
Code outside the default function runs once per VU during initialization. Use this for:
Loading data from files
Defining reusable variables
Configuring constants
import http from 'k6/http' ;
import { sleep } from 'k6' ;
// Init context - runs once per VU
const baseUrl = __ENV . BASE_URL || 'https://quickpizza.grafana.com' ;
const headers = { 'Content-Type' : 'application/json' };
export const options = {
vus: 10 ,
duration: '30s' ,
};
// VU context - runs repeatedly
export default function () {
http . get ( baseUrl , { headers: headers });
sleep ( 1 );
}
Avoid expensive operations in the init context that run for every VU. Use setup() for operations that should run only once for the entire test.
Use environment variables
Make your tests flexible by using environment variables:
import http from 'k6/http' ;
import { sleep } from 'k6' ;
// Read from environment variable with fallback
const baseUrl = __ENV . BASE_URL || 'https://quickpizza.grafana.com' ;
const vus = __ENV . VUS || 10 ;
export const options = {
vus: vus ,
duration: '30s' ,
};
export default function () {
http . get ( baseUrl );
sleep ( 1 );
}
Run with custom environment variables:
k6 run -e BASE_URL=https://api.example.com -e VUS= 50 my-first-test.js
Extending your script
Now that you understand the basics, explore these capabilities:
Multiple requests Add multiple http.get() or http.post() requests to simulate complex user flows
Thresholds Set performance requirements with thresholds that fail tests if not met
Custom metrics Track business-specific metrics using Counter, Gauge, Rate, and Trend
Example: Complete test script
Here’s a more complete example with checks, thresholds, and custom metrics:
import http from 'k6/http' ;
import { check , sleep } from 'k6' ;
import { Counter } from 'k6/metrics' ;
// Custom metric
const pizzaOrders = new Counter ( 'pizza_orders' );
// Test configuration
export const options = {
stages: [
{ duration: '1m' , target: 20 },
{ duration: '3m' , target: 20 },
{ duration: '1m' , target: 0 },
],
thresholds: {
'http_req_duration' : [ 'p(95)<500' ], // 95% of requests under 500ms
'http_req_failed' : [ 'rate<0.01' ], // Less than 1% error rate
'checks' : [ 'rate>0.95' ], // 95% of checks pass
},
};
const baseUrl = __ENV . BASE_URL || 'https://quickpizza.grafana.com' ;
export default function () {
// Homepage
let res = http . get ( ` ${ baseUrl } /` );
check ( res , {
'homepage loaded' : ( r ) => r . status === 200 ,
});
sleep ( 1 );
// View menu
res = http . get ( ` ${ baseUrl } /api/pizza` );
check ( res , {
'menu loaded' : ( r ) => r . status === 200 ,
'has pizza options' : ( r ) => r . json (). length > 0 ,
});
sleep ( 2 );
// Place order (simulated)
res = http . post ( ` ${ baseUrl } /api/order` , JSON . stringify ({
pizza: 'margherita' ,
quantity: 1 ,
}), {
headers: { 'Content-Type' : 'application/json' },
});
const orderSuccess = check ( res , {
'order placed' : ( r ) => r . status === 200 || r . status === 201 ,
});
if ( orderSuccess ) {
pizzaOrders . add ( 1 );
}
sleep ( 1 );
}
Next steps
You’ve created your first k6 test! Continue learning:
Understanding Results Learn how to read and analyze k6 test results
Using k6 Options Explore all available configuration options
HTTP Requests Master making HTTP requests with k6
Test Examples Browse real-world k6 test examples