Your site works fine with one user. With ten it still holds. Then comes Black Friday, a campaign launch, a viral post. And the server goes down. You lost sales, you lost trust. We see it every day: businesses discovering the limits of their infrastructure only when it's too late. Performance tests are not optional. They are what separates a professional website from a gamble.
How does k6 compare to Artillery for load testing?
k6 and Artillery are both open-source load testing tools, but they start from different philosophies. k6 is written in Go, uses JavaScript for scripts, and is designed for CI/CD integration. Artillery is Node.js based, uses YAML/JSON configurations, and is simpler for quick tests. At Meteora Web, we use both. We prefer k6 for realistic user simulations – navigating pages, submitting forms, uploading files. We keep Artillery for quick smoke tests on API endpoints.
Key difference: k6 runs in a single-threaded Go process, consuming fewer resources. Artillery, being Node, can be heavier with many users. To simulate 10,000 users, k6 wins. For a quick route test, Artillery is more immediate.
Practical example: k6 test on a contact form
Here's a k6 script that sends 5 requests per second for 30 seconds to a POST endpoint:
Sponsored Protocol
import http from 'k6/http';
import { sleep, check } from 'k6';
export let options = {
stages: [
{ duration: '30s', target: 5 },
],
};
export default function () {
let url = 'https://yoursite.com/api/contact';
let payload = JSON.stringify({ name: 'Test', email: 'test@example.com', message: 'Simulated load' });
let params = { headers: { 'Content-Type': 'application/json' } };
let res = http.post(url, payload, params);
check(res, { 'status 200': (r) => r.status === 200 });
sleep(1);
}
What it does: each iteration sends a POST, checks status, then waits 1 second. The test linearly scales to 5 iterations per second. Run with k6 run script.js.
Which to choose for performance testing: k6 or Artillery?
It depends. If your site is based on WordPress or a traditional CMS, and you want to test full page loads (HTML, CSS, JS, images), k6 is better because you can write complex scripts with data extraction and cookies. Artillery is better for simple APIs: define a YAML with requests and go.
A real case: a client e-commerce with WooCommerce. Before a promotion launch, we used k6 to simulate 50 users browsing, adding to cart, and checking out. k6 allowed us to handle session cookies and the cart. With Artillery we would have written more manual code. With k6 it was straightforward.
Sponsored Protocol
If you need to test an isolated microservice (e.g. login API), Artillery is faster to set up. Here's an Artillery example:
config:
target: 'https://api.yourservice.com'
phases:
- duration: 60
arrivalRate: 10
scenarios:
- flow:
- post:
url: '/login'
json:
username: 'test'
password: 'test'
capture:
- json: '$.token'
as: 'token'
Run with artillery run test.yml. Simple, right?
How to write a k6 load test that simulates real users?
A common mistake: testing only the endpoint, not the user flow. A real user arrives from the homepage, clicks, searches, fills forms. You should replicate that. k6 allows you to create scripts with multiple steps, extract data from responses, and use them in subsequent requests. Here's a simplified purchase flow example:
import http from 'k6/http';
import { sleep, check } from 'k6';
export default function () {
// 1. Homepage
let home = http.get('https://yourstore.com/');
check(home, { 'homepage OK': (r) => r.status === 200 });
sleep(2);
// 2. Search for a product
let search = http.get('https://yourstore.com/?s=shirt');
check(search, { 'search OK': (r) => r.status === 200 });
sleep(1);
// 3. Add to cart
let addCart = http.post('https://yourstore.com/cart', {
product_id: 123,
quantity: 1
});
check(addCart, { 'added to cart': (r) => r.status === 200 });
sleep(1);
// 4. Checkout page
let checkout = http.get('https://yourstore.com/checkout/');
check(checkout, { 'checkout OK': (r) => r.status === 200 });
sleep(1);
}
Note: we used sleep() to simulate reading time. You can vary times with random to mimic human behavior. k6 also has the k6/execution module for data like VU ID.
Sponsored Protocol
How to interpret load test results?
Two key metrics: response time (95th percentile) and error rate. If the 95th percentile exceeds 2 seconds for a page, you need to optimize. If there are 5xx errors, the server cannot handle it. k6 produces detailed output. We always look at the http_req_duration chart.
Sponsored Protocol
A practical tip: test under normal load and under stress. Normal load: 10-20 concurrent users for a medium site. Stress: double until you see degradation. Note the breaking point.
Example k6 output:
http_req_duration..............: avg=1.2s min=0.3s med=1.1s max=4.5s 90% 2.1s 95% 2.8s
http_req_failed................: 2.00% ✓ 80 ✗ 3920
Here the 95% responds within 2.8 seconds — acceptable for an API, but for a webpage we'd want under 2 seconds. The 2% error rate is too high; you need to investigate.
How to integrate k6 into your CI/CD pipeline?
Running performance tests on every deploy is the best way to avoid regressions. k6 integrates with GitHub Actions, GitLab CI, Jenkins. At Meteora Web, we do this for every project we release. Here's an example GitHub Actions workflow:
name: Load test
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run k6 test
uses: grafana/k6-action@v0.3.0
with:
filename: tests/load.js
flags: --vus 10 --duration 30s
Important: in your CI environment, do not test the production server! Use a staging environment. And set thresholds to fail the pipeline if performance degrades.
Sponsored Protocol
Common mistakes to avoid in performance testing
1. Testing only locally. Local network has zero latency. You must test on a remote server or an environment that simulates your users' distance.
2. Forgetting the database. Many tests ignore queries. If your site does 100 queries per page, under load the database collapses. Use tools like k6/x/dbi or monitor DB load.
3. Not testing static resources. k6 can also simulate loading images and CSS using k6/browser (browser mode). For more realistic tests, use the k6 browser module.
4. Ignoring system limits. Open ports, file handles, network connections. Make sure your OS allows enough simultaneous connections.
What to do next
- Install k6 on your local machine:
brew install k6(Mac),choco install k6(Windows), or download the binary from k6.io. - Write a simple test for your homepage. Run with 10 users for 30 seconds. Look at response times.
- Set thresholds in your test: e.g.,
thresholds: { http_req_duration: ['p(95)<2000'] }. This fails the test if the 95th percentile exceeds 2 seconds. - Integrate the test into your deploy with GitHub Actions or GitLab CI. Make it fail before code reaches production.
- Read the official documentation: k6 docs and Artillery docs. We consult them daily.
Don't wait for a bottleneck to cost you a customer. Start today.
For a deeper dive into the entire testing process, read our pillar guide: Software Testing Pyramid, Automation, and Strategies for Code That Doesn't Keep You Awake (link placeholder – adjust if needed).