k6 is faster than JMeter because it’s written in Go and uses a single process to manage load, while JMeter is Java-based and typically requires multiple JVMs or threads that can become a bottleneck.

Let’s see k6 in action. Imagine we want to test a simple API endpoint that returns a greeting.

First, we need to install k6. You can download it from the official k6 website or use a package manager like Homebrew on macOS:

brew install k6

Now, let’s write a basic k6 script in JavaScript. Save this as test.js:

import http from 'k6/http';
import { sleep } from 'k6';

export let options = {
  vus: 100, // Number of virtual users
  duration: '30s', // Duration of the test
};

export default function () {
  http.get('http://localhost:3000/greeting');
  sleep(1); // Pause for 1 second between iterations
}

This script defines 100 virtual users (vus) that will run for 30 seconds (duration). Each virtual user will make a GET request to http://localhost:3000/greeting and then pause for 1 second before repeating.

To run this, first, start a simple web server that responds to /greeting. Here’s a basic Node.js example using Express (save as server.js):

const express = require('express');
const app = express();
const port = 3000;

app.get('/greeting', (req, res) => {
  res.send('Hello from the server!');
});

app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
});

Run the server:

node server.js

Now, run the k6 test from a different terminal window:

k6 run test.js

You’ll see output like this:

          /\      | cyclohexane
         /  \     |
        /    \    | http request
       /______\   |
      /        \  |
     /__________\ |
    /            \|

  Scenarios:
    default:
      Target: 100 VUs, duration: 30s

  Execution:
    start: 2023-10-27 10:00:00 UTC
    end:   2023-10-27 10:00:30 UTC
    total: 30s

  Checks:
    http_req_failed: 0.00% ✓

  Data:
    http_req_duration:
      min: 1.20ms
      med: 5.50ms
      max: 50.00ms
    http_req_failed: 0.00%
    http_req_receiving:
      min: 0.10ms
      med: 0.50ms
      max: 10.00ms
    http_req_sending:
      min: 0.10ms
      med: 0.30ms
      max: 5.00ms
    http_req_tls:
      min: 0.00ms
      med: 0.00ms
      max: 0.00ms
    http_req_waiting:
      min: 0.90ms
      med: 4.50ms
      max: 40.00ms
    http_req_connecting:
      min: 0.00ms
      med: 0.00ms
      max: 0.00ms
    http_req_duration:
      min: 1.20ms
      med: 5.50ms
      max: 50.00ms
    http_req_failed: 0.00%
    http_req_receiving:
      min: 0.10ms
      med: 0.50ms
      max: 10.00ms
    http_req_sending:
      min: 0.10ms
      med: 0.30ms
      max: 5.00ms
    http_req_tls:
      min: 0.00ms
      med: 0.00ms
      max: 0.00ms
    http_req_waiting:
      min: 0.90ms
      med: 4.50ms
      max: 40.00ms
    http_req_connecting:
      min: 0.00ms
      med: 0.00ms
      max: 0.00ms
    ... (more metrics)

The core problem k6 solves is efficient, high-volume load generation from a single machine. Unlike JMeter, which often spawns multiple JVM processes or threads that can contend for resources and become a bottleneck themselves, k6 is built on Go. Go’s goroutines are incredibly lightweight, allowing k6 to manage thousands of concurrent virtual users within a single process without significant overhead. This means you can generate much higher load from a single k6 instance compared to a similarly configured JMeter setup, leading to more accurate results and reduced infrastructure costs for your load testing.

The options object is where you define your test’s execution parameters. vus (virtual users) determines how many concurrent users will hit your application, and duration sets how long the test will run. The default function is the heart of your test, defining the actions each virtual user performs. Here, http.get makes the request, and sleep(1) introduces a delay, simulating think time or the time between user actions.

The real power comes from k6’s extensibility. You can write complex scenarios involving multiple requests, conditional logic, and data parameterization using JavaScript. k6 also offers a rich set of built-in modules for HTTP requests, WebSocket communication, and more, all designed for performance.

One aspect that often surprises people is how k6 handles scripting. While it uses JavaScript, it’s a highly optimized, server-side execution environment designed for performance. It’s not a full browser DOM or Node.js environment. This means you can’t use window or document objects directly. Instead, you interact with the k6 API (like k6/http) to perform network operations. This focused environment is key to k6’s speed, as it avoids the overhead of a general-purpose JavaScript runtime.

Beyond basic scripting, k6 excels at integrating into CI/CD pipelines. You can easily run k6 tests as part of your build process, automatically catching performance regressions before they reach production. Its clear output and JSON reporting format make it straightforward to parse results and trigger alerts based on performance thresholds.

The next step in mastering k6 is exploring its advanced features like custom metrics, stages for gradual load increase, and integration with tools like Grafana for real-time monitoring.

Want structured learning?

Take the full Jmeter course →