load testing go apis with k6

A practical introduction to load testing Go APIs using k6, with examples and best practices.

load testing go apis with k6

Performance testing is essential for ensuring your Go APIs can handle real-world traffic. k6 is a modern, open-source load testing tool that makes it easy to write, run, and automate performance tests.

why k6?

  • Scriptable: Write tests in JavaScript
  • Developer-friendly: CLI and cloud options
  • Powerful: Supports checks, thresholds, and custom metrics
  • CI/CD ready: Integrates with pipelines

installing k6

On macOS:

1
brew install k6

Or see the official docs for other platforms.

example: simple get test

Create a file named script.js:

1
2
3
4
5
6
7
8
import http from 'k6/http';
import { check, sleep } from 'k6';

export default function () {
    const res = http.get('https://test-api.example.com/');
    check(res, { 'status is 200': (r) => r.status === 200 });
    sleep(1);
}

Run the test:

1
k6 run script.js

example: load testing a go api endpoint

Suppose you have a Go API at http://localhost:8080/api/add that accepts POST requests:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import http from 'k6/http';
import { check } from 'k6';

export let options = {
    vus: 10, // virtual users
    duration: '30s',
};

export default function () {
    const payload = JSON.stringify({ a: 2, b: 3 });
    const params = { headers: { 'Content-Type': 'application/json' } };
    const res = http.post('http://localhost:8080/api/add', payload, params);
    check(res, {
        'status is 200': (r) => r.status === 200,
        'result is 5': (r) => JSON.parse(r.body).result === 5,
    });
}

more k6 examples

example: parameterized requests

For example, you can test endpoints with different parameters or payloads using k6.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import http from 'k6/http';
import { check } from 'k6';

const testCases = [
    { a: 1, b: 2, want: 3 },
    { a: 0, b: 0, want: 0 },
    { a: -1, b: 1, want: 0 },
];

export default function () {
    const i = Math.floor(Math.random() * testCases.length);
    const tc = testCases[i];
    const payload = JSON.stringify({ a: tc.a, b: tc.b });
    const params = { headers: { 'Content-Type': 'application/json' } };
    const res = http.post('http://localhost:8080/api/add', payload, params);
    check(res, {
        'status is 200': (r) => r.status === 200,
        'result is correct': (r) => JSON.parse(r.body).result === tc.want,
    });
}

example: custom metrics and thresholds

k6 allows you to define custom metrics and set thresholds for pass/fail criteria.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import http from 'k6/http';
import { Trend } from 'k6/metrics';

export let responseTime = new Trend('response_time');

export let options = {
    thresholds: {
        'response_time': ['p(95)<500'], // 95% of requests should be <500ms
    },
};

export default function () {
    const res = http.get('http://localhost:8080/api/health');
    responseTime.add(res.timings.duration);
}

example: testing authentication

To test authenticated endpoints, you can add tokens or credentials to verify verified end points.

1
2
3
4
5
6
7
8
import http from 'k6/http';

export default function () {
    const loginRes = http.post('http://localhost:8080/api/login', JSON.stringify({ user: 'test', pass: 'test' }), { headers: { 'Content-Type': 'application/json' } });
    const token = JSON.parse(loginRes.body).token;
    const params = { headers: { 'Authorization': `Bearer ${token}` } };
    const res = http.get('http://localhost:8080/api/protected', params);
}

useful k6 features

  • Checks: Validate response data
  • Thresholds: Set performance goals
  • Scenarios: Simulate different traffic patterns
  • Metrics: Built-in and custom

integrating with ci/cd

k6 can be run in CI pipelines to catch performance regressions early. See the k6 docs for details.

best practices

  • Start with small loads, then scale up
  • Test realistic scenarios
  • Monitor system resources during tests
  • Automate performance tests in CI/CD

alternatives to k6

  • Apache JMeter: Java-based, GUI-heavy, powerful but less developer-friendly and harder to automate in CI/CD.
  • Gatling: Scala-based, good for complex scenarios, but requires Scala/Java knowledge.
  • Locust: Python-based, scriptable, but less performant at high concurrency and less integrated with modern JS/TS stacks.
  • Artillery: Node.js-based, good for HTTP and WebSocket, but less feature-rich for advanced metrics and thresholds.

why choose k6?

  • Modern scripting: Write tests in JavaScript/TypeScript, familiar to most developers.
  • Developer experience: CLI, cloud, and local options; easy to version and review test scripts.
  • Performance: Efficient, written in Go, supports high concurrency with low resource usage.
  • Automation: Designed for CI/CD, integrates with GitHub Actions, GitLab CI, Jenkins, and more.
  • Rich features: Built-in checks, thresholds, custom metrics, and flexible scenarios.
  • Active community: Well-documented, open-source, and widely adopted.

Unlike its balance of power, usability and modern developer workflow, k6 is an excellent choice for teams looking to automate and scale their API performance testing.


Using k6, it is easy to ensure that your Go APIs are fast and reliable under load. Test it out and make performance part of your development workflow?

Built with Hugo
Theme Stack designed by Jimmy