
Load testing is crucial for ensuring applications can handle high traffic. Whether it is Black Friday sales or a major product launch, ensuring stability under load prevents crashes and poor user experiences.
This guide explores load testing and K6, a powerful tool that simplifies the process of performance testing. We will cover the fundamentals of load testing and demonstrate how to use K6 to test applications effectively.
What is Load Testing and Why K6?
Understanding Load Testing (The Simple Way)
Imagine you're throwing a party at your house. You've planned for 20 friends, but what if 100 people show up? Will your living room handle it? Will you have enough snacks? Will the music system still work?
Load testing is basically the same thing, but for websites and applications.
It's a way to check if your website can handle lots of people using it at the same time without crashing, slowing down, or throwing errors. Just like you'd want to know if your house can handle a big party, developers want to know if their website can handle a big crowd of users.
Think about it this way:
Small load: 10 people browsing your online store - everything works smoothly
Medium load: 100 people - things might slow down a bit
Heavy load: 1000 people - will your site survive or crash?
Load testing helps you find out the answers to these questions BEFORE your users experience problems.
Enter K6: A Modern Load Testing Tool
K6 is a developer-centric load testing tool designed to simulate thousands of users accessing a website simultaneously.
Why is K6 so special?
Unlike legacy testing tools that can be complex and cumbersome, K6 is modern, lightweight, and easy to integrate into development workflows.
Here's what makes K6 awesome:
It speaks JavaScript: If you know a bit of JavaScript (or even if you don't, you'll pick it up!), you can write K6 tests. No need to learn a completely new language.
It's fast: K6 can simulate thousands of users on your laptop. It's like having a whole stadium of people testing your app, but they're all virtual.
It works everywhere: You can run K6 on your computer, on a server, or even set it up to run automatically every time you update your code.
It's free and open-source: Yep, you don't need to pay anything to use it!
Think of K6 as your testing sidekick - it does the heavy lifting of simulating users while you focus on making sure your application can handle them.
Benefits of K6: Why You'll Love It
Here is why K6 is an essential tool for testing. These features provide significant benefits for developers and testers.
1. Super Easy to Learn
Since K6 uses JavaScript, there is no need to learn a proprietary scripting language. Knowledge of JavaScript allows for quick adoption.
Here's a simple example - this is literally all you need to test a website:
import http from 'k6/http';
export default function () {
http.get('https://your-website.com');
}
That's it! Just three lines of code, and you're testing a website. Easy, right?
2. You Can See Results Clearly
K6 doesn't just run tests and leave you guessing. It gives you clear, easy-to-understand results. It tells you things like:
How fast your website responded
How many requests failed
How many virtual users were active
Whether your website passed or failed your test
It's like getting a report card, but for your website!
3. Works With Your Existing Tools
K6 plays nicely with other tools you might already be using. You can send results to Grafana (for beautiful charts), integrate it with your continuous integration pipeline, or export data to analyze later.
Think of it like LEGO blocks - K6 connects with other tools seamlessly to build exactly what you need.
4. It's Built for Modern Development
Unlike older tools that feel like they're from the 1990s, K6 is built for how we develop software today. You can:
Run it from the command line (your terminal)
Put your tests in version control (like Git)
Run tests automatically when you deploy code
Share tests easily with your team
5. Realistic Testing
K6 doesn't just send simple requests. You can make it act like real users:
Log in to your website
Browse different pages
Add items to a shopping cart
Submit forms
Upload files
This means your tests actually reflect how real people will use your application!
6. You Can Test Anything
Whether you're testing:
A simple website
A complex web application
An API (the backend that powers apps)
A mobile app's backend
A real-time system
K6 can handle it all. It's like a Swiss Army knife for load testing!
Types of Load Testing: Different Tests for Different Situations
Not all load tests are the same. Different situations require different testing strategies to ensure comprehensive performance validation.
We will explore the different types of load tests and explain when to use each one.
1. Load Testing (The Standard Check-up)
What it is: This is your basic, everyday test. It's like a regular health check-up at the doctor's office.
When to use it: When you want to see if your application performs well under normal, expected conditions.
The scenario: Imagine your online store usually has about 50 people shopping at the same time during business hours. A load test would simulate exactly that - 50 users browsing, searching, and buying products.
Real-world example: You're launching a blog, and you expect about 100 people to read it simultaneously. You'd run a load test with 100 virtual users to make sure everything works smoothly.
What you're checking:
Does the website respond quickly?
Are all pages loading correctly?
Is everything working as expected?
Think of this as making sure your car runs smoothly during your daily commute.
2. Stress Testing (Finding the Breaking Point)
What it is: This is where you push your application to its limits and beyond. It's like asking "How much weight can this bridge hold before it collapses?"
When to use it: When you need to know the maximum capacity of your system and what happens when you exceed it.
The scenario: You keep adding more and more users until something breaks. Maybe you start with 100 users, then 200, then 500, then 1000... until you see errors or slowdowns.
Real-world example: Your website normally handles 100 users, but you want to know what happens if 500 or 1000 people show up. At what point does it start failing?
What you're checking:
What's the maximum number of users your system can handle?
How does it fail when overloaded? (Does it crash completely or just slow down?)
How quickly does it recover once the load decreases?
Think of this as testing how many people can fit in an elevator before the alarm goes off.
3. Spike Testing (The Surprise Attack)
What it is: This simulates a sudden, massive increase in users - like when a celebrity tweets about your product and suddenly everyone rushes to your website at once.
When to use it: When you need to see if your system can handle sudden traffic surges.
The scenario: Your website is humming along with 20 users, and then BOOM! Suddenly 500 people arrive within 10 seconds. Can your system handle the shock?
Real-world example:
You're mentioned on a popular TV show
Your product goes viral on social media
A news article links to your site
Flash sale starts
What you're checking:
Does your system crash when hit with sudden traffic?
How long does it take to recover?
Do users get errors during the spike?
Think of this as everyone in the office trying to use the microwave at exactly 12:00 PM during lunch break. Can it handle the sudden demand?
4. Soak Testing (The Endurance Marathon)
What it is: This is a long-duration test that runs for hours or even days. It's like a marathon instead of a sprint.
When to use it: When you want to find problems that only appear after your application has been running for a while.
The scenario: You run a moderate load (say, 100 users) continuously for 4, 8, or even 24 hours.
Real-world example: Your application seems fine for the first hour, but after running all day, it starts slowing down or using too much memory. Soak testing would catch this!
What you're checking:
Are there memory leaks? (Does your app slowly eat up more and more memory until it crashes?)
Do database connections pile up over time?
Does performance degrade after hours of use?
Are there any "time bombs" waiting to explode?
Think of this as checking if your phone battery lasts all day with normal use, not just for the first hour.
5. Ramp-Up Testing (The Gradual Increase)
What it is: This is where you slowly increase the number of users over time, like gradually filling a bathtub instead of blasting the water at full force.
When to use it: When you want to see how your system behaves as load increases gradually.
The scenario: Start with 10 users, then slowly increase to 20, then 50, then 100 over a period of 10-20 minutes.
Real-world example: Your store opens at 9 AM, and customers trickle in throughout the morning. By noon, you have your peak crowd. Ramp-up testing simulates this gradual increase.
What you're checking:
At what point does performance start to degrade?
Does your system scale smoothly, or are there sudden performance drops?
Can your auto-scaling (if you have it) keep up with increasing demand?
Think of this as watching a concert venue fill up - it starts empty, but gradually gets fuller until it's packed.
6. Smoke Testing (The Quick Sanity Check)
What it is: A quick, light test with just a few users to make sure your application basically works.
When to use it: After every code change or deployment, just to make sure you didn't break anything obvious.
The scenario: Run just 1-5 virtual users through your most important features for a few minutes.
Real-world example: Before running a full test suite, you do a smoke test to make sure the login page works, the homepage loads, and the basic functions aren't broken.
What you're checking:
Does the application start up correctly?
Are the critical features working?
Is it even worth running more detailed tests?
Think of this as turning on your car before a road trip to make sure it starts - you're not testing everything, just making sure it's basically functional.
7. Scalability Testing (Planning for Growth)
What it is: Testing how well your application grows when you add more resources (like more servers).
When to use it: When you're planning for future growth or want to know if adding more servers will actually help.
The scenario: Test with 100 users on one server, then test with 100 users on two servers, then three servers, and see if performance improves proportionally.
Real-world example: Your startup is growing! You want to know if adding more servers will let you handle 10x more users, or if there are other bottlenecks.
What you're checking:
If you double your servers, can you handle double the users?
Are there bottlenecks that prevent scaling? (Like a single database that everything depends on)
What's the most cost-effective way to scale?
Think of this as figuring out whether hiring more cashiers will actually make the checkout line move faster, or if the problem is something else (like a slow credit card machine).
Quick Summary Table (for easy reference):
| Test Type | Duration | Load Pattern | What It Tests |
| Load | Medium (minutes) | Steady, expected load | Normal performance |
| Stress | Medium | Gradually increasing until failure | Maximum capacity |
| Spike | Short | Sudden massive increase | Shock resistance |
| Soak | Long (hours/days) | Steady, moderate load | Long-term stability |
| Ramp-Up | Medium | Gradually increasing | Scaling behavior |
| Smoke | Very short | Minimal load | Basic functionality |
| Scalability | Varies | Testing with different resources | Growth potential |
Writing Your First K6 Load Testing Script
Now, we will write some K6 scripts. We will start with a simple example and gradually add complexity.
Step 1: Installing K6
Before we can write scripts, we need to install K6 on your computer. It's really easy!
For Mac users (using Homebrew):
brew install k6
For Windows users (using Chocolatey):
choco install k6
For Linux users:
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
To check if it's installed correctly, type:
k6 version
If you see a version number, the installation was successful.
Step 2: Your First Super Simple Script
Let's create your very first K6 script. Open your favorite text editor and create a file called my-first-test.js.
Type this code:
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
Here is an explanation of each line:
import http from 'k6/http';- This is like getting a tool from a toolbox. We're telling K6 we want to use the HTTP tool to make web requests.import { sleep } from 'k6';- We're getting another tool that lets our script "sleep" or wait.export default function () { ... }- This is the main part of our test. Think of it as the recipe instructions. Everything inside the curly braces{ }will be repeated by each virtual user.http.get('https://test.k6.io');- This makes our virtual user visit the website (just like clicking a link in your browser).sleep(1);- This makes the virtual user wait for 1 second before doing the next thing. Real users don't click things instantly, they read, they think - this makes it more realistic.
To run this script, open your terminal, go to the folder where you saved the file, and type:
k6 run my-first-test.js
You have successfully run your first load test.
Step 3: Adding Virtual Users (Making It More Realistic)
Right now, our test only runs 1 virtual user for a short time. Let's make it more interesting by adding more users!
Update your script to look like this:
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
What's new?
export const options = { ... }- This is where we configure our test settings.vus: 10- VUs means "Virtual Users". We're telling K6 to simulate 10 people using the website at the same time.duration: '30s'- The test will run for 30 seconds.
So now, 10 virtual users will repeatedly visit the website for 30 seconds. Each user will visit the site, wait 1 second, visit again, wait 1 second, and keep doing this until the 30 seconds are up.
Run it with:
k6 run my-first-test.js
You'll see more interesting results now!
Step 4: Building a Load Test (Ramping Up Users)
Now let's create a proper load test where users gradually join and then leave. This is more realistic than everyone showing up at exactly the same time.
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 20 }, // Ramp up to 20 users over 1 minute
{ duration: '3m', target: 20 }, // Stay at 20 users for 3 minutes
{ duration: '1m', target: 0 }, // Ramp down to 0 users over 1 minute
],
};
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
Understanding stages:
Think of stages like acts in a play:
Act 1 (
{ duration: '1m', target: 20 }): Over 1 minute, gradually add users until we have 20. It's like people slowly entering a store when it opens.Act 2 (
{ duration: '3m', target: 20 }): Keep 20 users active for 3 minutes. This is the "steady state" where we see how the system performs under normal load.Act 3 (
{ duration: '1m', target: 0 }): Gradually remove all users over 1 minute. Like people leaving the store at closing time.
This gives us a 5-minute test that simulates realistic user behavior!
Step 5: Creating a Spike Test
Remember spike testing? Let's create a script for that sudden surge of users:
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 20 }, // Normal load: 20 users
{ duration: '10s', target: 200 }, // SPIKE! Jump to 200 users in 10 seconds
{ duration: '1m', target: 200 }, // Hold the spike for 1 minute
{ duration: '30s', target: 20 }, // Back down to normal
{ duration: '30s', target: 0 }, // End the test
],
};
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
See how we jump from 20 to 200 users in just 10 seconds? That's the spike! This tests if your website can handle a sudden viral moment.
Step 6: Building a Stress Test
For stress testing, we keep pushing the limits higher and higher:
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 }, // Ramp to 50 users
{ duration: '2m', target: 100 }, // Then to 100 users
{ duration: '2m', target: 150 }, // Then to 150 users
{ duration: '2m', target: 200 }, // Then to 200 users
{ duration: '2m', target: 250 }, // Keep pushing...
{ duration: '2m', target: 0 }, // Ramp down
],
};
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
This gradually increases the load every 2 minutes. You'll see at which point your system starts to struggle!
Step 7: Creating a Soak Test
For soak testing, we run a moderate load for a LONG time:
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
{ duration: '5m', target: 50 }, // Ramp up to 50 users
{ duration: '4h', target: 50 }, // Hold at 50 users for 4 HOURS!
{ duration: '5m', target: 0 }, // Ramp down
],
};
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
Warning: This will run for over 4 hours! Make sure your computer doesn't go to sleep. Soak tests are great to run overnight or while you're doing other work.
Step 8: Adding Checks (Making Sure Things Work)
So far, we're just visiting pages, but we're not checking if they actually work correctly. Let's add some "checks" - these are like little tests within our test:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
};
export default function () {
const response = http.get('https://test.k6.io');
// Check if the response is good
check(response, {
'status is 200': (r) => r.status === 200,
'page loaded fast': (r) => r.timings.duration < 500,
});
sleep(1);
}
What's happening here?
const response = http.get(...)- We're saving the response from the website so we can check it.check(response, { ... })- This is where we verify things:'status is 200'- Checks if the page loaded successfully (200 means "OK" in HTTP language)'page loaded fast'- Checks if the page loaded in less than 500 milliseconds (half a second)
If these checks fail, K6 will tell you! This helps you catch problems automatically.
Step 9: Testing Real User Behavior (Multiple Pages)
Real users don't just visit one page - they browse around! Let's simulate that:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '1m',
};
export default function () {
// Visit the homepage
let response = http.get('https://test.k6.io');
check(response, { 'homepage loaded': (r) => r.status === 200 });
sleep(2); // User reads the homepage for 2 seconds
// Visit the contacts page
response = http.get('https://test.k6.io/contacts.php');
check(response, { 'contacts page loaded': (r) => r.status === 200 });
sleep(2); // User reads the contacts page
// Visit the news page
response = http.get('https://test.k6.io/news.php');
check(response, { 'news page loaded': (r) => r.status === 200 });
sleep(1);
}
Now our virtual users behave more like real people - they visit multiple pages and spend time reading!
Step 10: Adding Thresholds (Pass or Fail)
Thresholds are like setting a grade for your test. If your website doesn't meet certain standards, the test will fail:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '1m',
thresholds: {
http_req_duration: ['p(95)<500'], // 95% of requests must complete in less than 500ms
http_req_failed: ['rate<0.01'], // Error rate must be less than 1%
checks: ['rate>0.95'], // 95% of checks must pass
},
};
export default function () {
const response = http.get('https://test.k6.io');
check(response, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
What do these thresholds mean?
http_req_duration: ['p(95)<500']- 95% of all requests should take less than 500 milliseconds. If they're slower, the test fails.http_req_failed: ['rate<0.01']- Less than 1% of requests should fail. If more than 1% fail, the test fails.checks: ['rate>0.95']- At least 95% of our checks should pass.
If any threshold is crossed, K6 will exit with an error code, which is perfect for automated testing systems!
Step 11: Making It Dynamic (Random User Behavior)
Let's make our test even more realistic by randomizing user behavior:
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '1m',
};
const pages = [
'https://test.k6.io',
'https://test.k6.io/contacts.php',
'https://test.k6.io/news.php',
'https://test.k6.io/my_messages.php',
];
export default function () {
// Pick a random page from our list
const randomPage = pages[Math.floor(Math.random() * pages.length)];
const response = http.get(randomPage);
check(response, { 'page loaded': (r) => r.status === 200 });
// Sleep for a random time between 1 and 3 seconds
sleep(Math.random() * 2 + 1);
}
Now each virtual user will visit random pages and wait for random amounts of time - just like real users!
Step 12: Complete Real-World Example
Let's put it all together with a comprehensive example that tests an e-commerce site:
import http from 'k6/http';
import { check, sleep, group } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 20 }, // Warm up
{ duration: '5m', target: 50 }, // Normal load
{ duration: '1m', target: 100 }, // Peak load
{ duration: '2m', target: 100 }, // Stay at peak
{ duration: '1m', target: 0 }, // Cool down
],
thresholds: {
http_req_duration: ['p(95)<1000'],
http_req_failed: ['rate<0.05'],
},
};
export default function () {
// Group related requests together for better reporting
group('Homepage Visit', function () {
const response = http.get('https://test.k6.io');
check(response, {
'homepage status is 200': (r) => r.status === 200,
'homepage loaded quickly': (r) => r.timings.duration < 800,
});
sleep(2);
});
group('Browse Products', function () {
const response = http.get('https://test.k6.io/news.php');
check(response, {
'products page loaded': (r) => r.status === 200,
});
sleep(3); // User browses products
});
group('View Contact Info', function () {
const response = http.get('https://test.k6.io/contacts.php');
check(response, {
'contacts page loaded': (r) => r.status === 200,
});
sleep(1);
});
}
This script:
Simulates realistic user traffic patterns
Groups related actions together
Has checks to verify everything works
Has thresholds to automatically pass/fail
Includes realistic wait times
Step 13: Running Your Tests and Understanding Results
When you run your test with k6 run my-test.js, you'll see output like this:
β homepage status is 200
β page loaded quickly
checks.........................: 100.00% β 450 β 0
data_received..................: 1.2 MB 40 kB/s
data_sent......................: 36 kB 1.2 kB/s
http_req_duration..............: avg=145.32ms min=98.32ms med=142.12ms max=312.43ms p(90)=198.43ms p(95)=234.12ms
http_reqs......................: 450 15/s
vus............................: 10 min=10 max=10
What does this mean?
checks: Shows how many checks passed (β) or failed (β)http_req_duration: How long requests took (avg=average, p(95)=95th percentile)http_reqs: Total number of requests madevus: Number of virtual users that ran
If everything is green with checkmarks, your test passed! π
Quick Reference: Common K6 Commands
# Run a basic test
k6 run script.js
# Run with custom number of users
k6 run --vus 50 --duration 1m script.js
# Save results to a JSON file
k6 run --out json=results.json script.js
# Run in quiet mode (less output)
k6 run --quiet script.js
And that's it! You now know how to write K6 load testing scripts from scratch. Start simple, test often, and gradually make your tests more sophisticated as you learn.
Remember: the best test is the one you actually run, so don't worry about making it perfect from the start. Just start testing!
Understanding the Impact
We have covered the essentials of load testing and K6:
β What load testing is and why it matters β Why K6 is an effective tool β The different types of load tests and when to use them β How to write K6 scripts from scratch β How to read and understand test results
Load testing is beneficial for projects of all sizes. Understanding how to test applications leads to better development practices and more robust software.
Recommendation: Start Small
Begin by testing a single feature with a small number of users. Run the test, analyze the results, and gradually increase complexity.





