Skip to main content
Performance Testing·Lesson 4 of 5

Load Testing with k6

Lighthouse tests one user at a time. Load testing answers a different question: how does your application perform when hundreds or thousands of users hit it simultaneously? k6 is a modern, developer-friendly load testing tool that uses JavaScript for test scripts.

What Is Load Testing?

Load testing simulates concurrent users to measure how your system handles traffic. It reveals:

  • Throughput: How many requests per second can your server handle?
  • Latency under load: Do response times degrade as users increase?
  • Breaking points: At what load does the system start failing?
  • Resource bottlenecks: Is it CPU, memory, database connections, or network bandwidth?

Installing k6

k6 is a standalone binary — no Node.js runtime needed:

# macOS
brew install k6

# Windows (with Chocolatey)
choco install k6

# Docker
docker run --rm -i grafana/k6 run - < script.js

# Or download from https://k6.io/docs/get-started/installation/

Writing Your First Load Test

Create a file called load-test.js:

Ctrl+Enter
HTML
CSS
JS
Preview

Run it:

k6 run load-test.js

Each virtual user (VU) executes the default function in a loop for the specified duration. The check() function validates response conditions, and sleep() simulates realistic user pauses between actions.

Ramp-Up Patterns

Real traffic does not arrive all at once. Use stages to simulate gradual increases:

Ctrl+Enter
HTML
CSS
JS
Preview

This pattern is called a "stepped load test." It helps you identify at what level of concurrency performance starts to degrade.

Other Common Patterns

  • Spike test: Ramp to a very high number quickly, then drop. Tests how the system handles sudden traffic surges.
  • Soak test: Run at moderate load for hours. Finds memory leaks and resource exhaustion over time.
  • Stress test: Gradually increase beyond expected capacity to find the breaking point.

Thresholds

Thresholds define pass/fail criteria for your load test. If any threshold is breached, k6 exits with a non-zero code — perfect for CI:

Ctrl+Enter
HTML
CSS
JS
Preview

The p(95) syntax means the 95th percentile — 95% of all requests should complete within the specified time. This is more meaningful than average response time because averages hide outliers.

Testing Multiple Endpoints

Real users do not just hit the homepage. Simulate a realistic scenario:

Ctrl+Enter
HTML
CSS
JS
Preview

Reading Results

After a test run, k6 prints a summary with key metrics:

  • http_req_duration: Response time statistics (avg, min, med, max, p90, p95, p99).
  • http_reqs: Total number of requests and requests per second.
  • http_req_failed: Percentage of failed requests.
  • vus: Number of active virtual users over time.
  • checks: How many checks passed versus failed.

For persistent storage and visualization, you can stream results to Grafana Cloud, InfluxDB, or a CSV file:

k6 run --out csv=results.csv load-test.js

Key Takeaways

  • k6 simulates concurrent users to reveal how your system performs under load.
  • Use stages for realistic ramp-up patterns instead of constant load.
  • Set thresholds to enforce performance requirements and fail CI when they are breached.
  • Focus on p95 response times, not averages — they reveal the experience of your slowest users.
  • Test multiple endpoints to simulate realistic user journeys.