K6 Testing Snippets

Snippet Testing

Ready-to-use K6 load testing scripts for common API testing scenarios with example outputs and performance metrics

What is this? Official Docs

Modern load testing tool using JavaScript to test API, microservices, and website performance at scale.

What is K6?

K6 is a modern, developer-friendly load testing tool built for testing the performance of APIs, microservices, and websites. Write tests in JavaScript and run them from the CLI or CI/CD pipeline.


📮 Testing - POST API Load Test

Load test a POST endpoint with JSON payload and performance thresholds.

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

export const options = {
  stages: [
    { duration: '1m', target: 50 },   // Ramp up to 50 users
    { duration: '3m', target: 50 },   // Stay at 50 users
    { duration: '1m', target: 0 },    // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'], // 95% of requests under 500ms
    http_req_failed: ['rate<0.01'],   // Less than 1% errors
  },
};

export default function () {
  const url = 'https://api.example.com/users';
  const payload = JSON.stringify({
    name: 'John Doe',
    email: 'john@example.com',
    role: 'developer',
  });

  const params = {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN_HERE',
    },
  };

  const res = http.post(url, payload, params);

  check(res, {
    'status is 201': (r) => r.status === 201,
    'response time < 500ms': (r) => r.timings.duration < 500,
    'has user id': (r) => JSON.parse(r.body).id !== undefined,
  });

  sleep(1);
}

Expected Output:

$ k6 run post-load-test.js

 status is 201
 response time < 500ms
 has user id

     checks.........................: 100.00% 9000 0
     data_received..................: 2.1 MB  42 kB/s
     data_sent......................: 540 kB  11 kB/s
     http_req_blocked...............: avg=1.2ms    min=0s     med=1ms    max=45ms   p(90)=2ms    p(95)=3ms
     http_req_connecting............: avg=1ms      min=0s     med=1ms    max=42ms   p(90)=2ms    p(95)=2.5ms
 http_req_duration..............: avg=245ms    min=120ms  med=230ms  max=480ms  p(90)=350ms  p(95)=420ms
     http_req_failed................: 0.00% 0 3000
     http_req_receiving.............: avg=0.5ms    min=0.1ms  med=0.4ms  max=5ms    p(90)=1ms    p(95)=1.5ms
     http_req_sending...............: avg=0.3ms    min=0.1ms  med=0.2ms  max=3ms    p(90)=0.5ms  p(95)=0.8ms
     http_req_tls_handshaking.......: avg=0ms      min=0s     med=0s     max=0s     p(90)=0s     p(95)=0s
     http_req_waiting...............: avg=244ms    min=119ms  med=229ms  max=479ms  p(90)=349ms  p(95)=419ms
     http_reqs......................: 3000    60/s
     iteration_duration.............: avg=1.24s    min=1.12s  med=1.23s  max=1.48s  p(90)=1.35s  p(95)=1.42s
     iterations.....................: 3000    60/s
     vus............................: 50      min=0     max=50
     vus_max........................: 50      min=50    max=50

 Thresholds passed

When to use:

  • Testing user registration endpoints
  • Load testing POST APIs
  • Validating API performance under load
  • Setting performance baselines

🔍 Testing - GET API Stress Test

Stress test a GET endpoint to find breaking points.

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

export const options = {
  stages: [
    { duration: '2m', target: 100 },  // Ramp up to 100 users
    { duration: '5m', target: 100 },  // Stay at 100 users
    { duration: '2m', target: 200 },  // Ramp up to 200 users
    { duration: '5m', target: 200 },  // Stay at 200 users
    { duration: '2m', target: 0 },    // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(99)<1000', 'p(95)<800', 'p(50)<400'],
    http_req_failed: ['rate<0.05'],
  },
};

export default function () {
  const url = 'https://api.example.com/products?page=1&limit=20';

  const params = {
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN_HERE',
    },
  };

  const res = http.get(url, params);

  check(res, {
    'status is 200': (r) => r.status === 200,
    'has products array': (r) => {
      const body = JSON.parse(r.body);
      return Array.isArray(body.products);
    },
    'response size ok': (r) => r.body.length < 100000,
  });

  sleep(0.5);
}

Expected Output:

$ k6 run get-stress-test.js

 status is 200
 has products array
 response size ok

     checks.........................: 100.00% 24000 0
     data_received..................: 48 MB   60 kB/s
     data_sent......................: 3.2 MB  4.0 kB/s
     http_req_blocked...............: avg=0.8ms    min=0s     med=0.5ms  max=35ms   p(90)=1.5ms  p(95)=2ms
     http_req_connecting............: avg=0.7ms    min=0s     med=0.5ms  max=32ms   p(90)=1.2ms  p(95)=1.8ms
 http_req_duration..............: avg=320ms    min=95ms   med=285ms  max=980ms  p(90)=520ms  p(95)=680ms  p(99)=890ms
     http_req_failed................: 0.00% 0 8000
     http_req_receiving.............: avg=2ms      min=0.2ms  med=1.5ms  max=25ms   p(90)=4ms    p(95)=6ms
     http_req_sending...............: avg=0.2ms    min=0.1ms  med=0.2ms  max=2ms    p(90)=0.4ms  p(95)=0.6ms
     http_req_waiting...............: avg=318ms    min=94ms   med=283ms  max=978ms  p(90)=518ms  p(95)=678ms
     http_reqs......................: 8000    100/s
     iteration_duration.............: avg=820ms    min=595ms  med=785ms  max=1.48s  p(90)=1.02s  p(95)=1.18s
     iterations.....................: 8000    100/s
     vus............................: 200     min=0     max=200
     vus_max........................: 200     min=200   max=200

 All thresholds passed

When to use:

  • Finding system capacity limits
  • Stress testing read-heavy APIs
  • Performance regression testing
  • Capacity planning

⚡ Testing - Spike Test (Sudden Traffic)

Test how your API handles sudden traffic spikes.

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

export const options = {
  stages: [
    { duration: '10s', target: 10 },   // Normal load
    { duration: '30s', target: 500 },  // Sudden spike!
    { duration: '1m', target: 500 },   // Sustained spike
    { duration: '10s', target: 10 },   // Recovery
  ],
  thresholds: {
    http_req_duration: ['p(95)<2000'], // More lenient during spikes
    http_req_failed: ['rate<0.1'],     // Allow 10% errors during spike
  },
};

export default function () {
  const res = http.get('https://api.example.com/health');

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time OK': (r) => r.timings.duration < 3000,
  });

  sleep(Math.random() * 2); // Random think time
}

Expected Output:

$ k6 run spike-test.js

 status is 200
 response time OK
  92% 4140 / 360

     checks.........................: 96.00% 8640 360
     data_received..................: 1.8 MB  18 kB/s
     data_sent......................: 450 kB  4.5 kB/s
     http_req_blocked...............: avg=2.5ms    min=0s     med=1ms    max=120ms  p(90)=5ms    p(95)=8ms
     http_req_connecting............: avg=2ms      min=0s     med=1ms    max=115ms  p(90)=4ms    p(95)=7ms
 http_req_duration..............: avg=850ms    min=180ms  med=650ms  max=2800ms p(90)=1500ms p(95)=1850ms
     http_req_failed................: 8.00% 360 4140
     http_req_receiving.............: avg=1.2ms    min=0.1ms  med=0.8ms  max=45ms   p(90)=2.5ms  p(95)=4ms
     http_req_sending...............: avg=0.4ms    min=0.1ms  med=0.3ms  max=8ms    p(90)=0.8ms  p(95)=1.2ms
     http_req_waiting...............: avg=848ms    min=179ms  med=649ms  max=2798ms p(90)=1498ms p(95)=1848ms
     http_reqs......................: 4500    45/s
     iteration_duration.............: avg=1.85s    min=1.18s  med=1.65s  max=4.8s   p(90)=2.5s   p(95)=3.2s
     iterations.....................: 4500    45/s
     vus............................: 10      min=10    max=500
     vus_max........................: 500     min=500   max=500

 Thresholds passed (degraded performance during spike expected)

When to use:

  • Testing auto-scaling behavior
  • Validating rate limiting
  • Black Friday / traffic surge preparation
  • DDoS resilience testing

🔐 Testing - Authentication Flow

Test authenticated POST requests with token refresh.

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

export const options = {
  vus: 20,
  duration: '2m',
  thresholds: {
    http_req_duration: ['p(95)<600'],
  },
};

// Login once per VU
export function setup() {
  const loginRes = http.post('https://api.example.com/auth/login', JSON.stringify({
    username: 'testuser',
    password: 'testpass123',
  }), {
    headers: { 'Content-Type': 'application/json' },
  });

  return { token: JSON.parse(loginRes.body).token };
}

export default function (data) {
  const params = {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${data.token}`,
    },
  };

  // Create a post
  const payload = JSON.stringify({
    title: 'Test Post',
    content: 'This is a test post content',
  });

  const res = http.post('https://api.example.com/posts', payload, params);

  check(res, {
    'post created': (r) => r.status === 201,
    'has post id': (r) => JSON.parse(r.body).id !== undefined,
  });

  sleep(2);
}

Expected Output:

$ k6 run auth-flow-test.js

 post created
 has post id

     checks.........................: 100.00% 2400 0
     data_received..................: 960 kB  8.0 kB/s
     data_sent......................: 384 kB  3.2 kB/s
     http_req_blocked...............: avg=0.6ms    min=0s     med=0.5ms  max=12ms   p(90)=1ms    p(95)=1.5ms
     http_req_connecting............: avg=0.5ms    min=0s     med=0.4ms  max=10ms   p(90)=0.9ms  p(95)=1.2ms
 http_req_duration..............: avg=285ms    min=145ms  med=270ms  max=580ms  p(90)=390ms  p(95)=450ms
     http_req_failed................: 0.00% 0 1200
     http_req_receiving.............: avg=0.8ms    min=0.2ms  med=0.6ms  max=8ms    p(90)=1.5ms  p(95)=2ms
     http_req_sending...............: avg=0.3ms    min=0.1ms  med=0.2ms  max=4ms    p(90)=0.5ms  p(95)=0.8ms
     http_req_waiting...............: avg=284ms    min=144ms  med=269ms  max=579ms  p(90)=389ms  p(95)=449ms
     http_reqs......................: 1200    10/s
     iteration_duration.............: avg=2.28s    min=2.14s  med=2.27s  max=2.58s  p(90)=2.39s  p(95)=2.45s
     iterations.....................: 1200    10/s
     vus............................: 20      min=20    max=20
     vus_max........................: 20      min=20    max=20

 All thresholds passed

When to use:

  • Testing login/signup flows
  • Validating JWT token handling
  • Session-based API testing
  • Auth service load testing

🔄 Testing - Multi-Endpoint Scenario

Test realistic user journey across multiple endpoints.

import http from 'k6/http';
import { check, group, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '1m', target: 30 },
    { duration: '3m', target: 30 },
    { duration: '1m', target: 0 },
  ],
  thresholds: {
    'group_duration{group:::User Journey}': ['p(95)<5000'],
    http_req_duration: ['p(95)<500'],
  },
};

export default function () {
  group('User Journey', function () {
    // 1. Browse products
    let res = http.get('https://api.example.com/products');
    check(res, { 'products loaded': (r) => r.status === 200 });
    sleep(1);

    // 2. View product details
    res = http.get('https://api.example.com/products/123');
    check(res, { 'product details loaded': (r) => r.status === 200 });
    sleep(2);

    // 3. Add to cart
    const cartPayload = JSON.stringify({ productId: 123, quantity: 1 });
    res = http.post('https://api.example.com/cart', cartPayload, {
      headers: { 'Content-Type': 'application/json' },
    });
    check(res, { 'added to cart': (r) => r.status === 201 });
    sleep(1);

    // 4. Checkout
    const checkoutPayload = JSON.stringify({
      paymentMethod: 'card',
      address: '123 Main St',
    });
    res = http.post('https://api.example.com/checkout', checkoutPayload, {
      headers: { 'Content-Type': 'application/json' },
    });
    check(res, { 'checkout success': (r) => r.status === 200 });
  });

  sleep(3);
}

Expected Output:

$ k6 run multi-endpoint-test.js

 products loaded
 product details loaded
 added to cart
 checkout success

     checks.........................: 100.00% 4800 0
     data_received..................: 9.6 MB  32 kB/s
     data_sent......................: 1.2 MB  4.0 kB/s
     group_duration.................: avg=2.8s     min=2.1s   med=2.7s   max=4.5s   p(90)=3.5s   p(95)=3.9s
 group_duration{group:::User Journey}: avg=2.8s     min=2.1s   med=2.7s   max=4.5s   p(90)=3.5s   p(95)=3.9s
     http_req_blocked...............: avg=0.7ms    min=0s     med=0.5ms  max=18ms   p(90)=1.2ms  p(95)=1.8ms
     http_req_connecting............: avg=0.6ms    min=0s     med=0.4ms  max=15ms   p(90)=1ms    p(95)=1.5ms
 http_req_duration..............: avg=298ms    min=125ms  med=280ms  max=485ms  p(90)=410ms  p(95)=450ms
     http_req_failed................: 0.00% 0 4800
     http_req_receiving.............: avg=1.2ms    min=0.2ms  med=0.9ms  max=12ms   p(90)=2.5ms  p(95)=3.5ms
     http_req_sending...............: avg=0.4ms    min=0.1ms  med=0.3ms  max=5ms    p(90)=0.7ms  p(95)=1ms
     http_req_waiting...............: avg=296ms    min=124ms  med=278ms  max=483ms  p(90)=408ms  p(95)=448ms
     http_reqs......................: 4800    16/s
     iteration_duration.............: avg=9.8s     min=9.1s   med=9.7s   max=11.5s  p(90)=10.5s  p(95)=10.9s
     iterations.....................: 1200    4/s
     vus............................: 30      min=0     max=30
     vus_max........................: 30      min=30    max=30

 All thresholds passed

When to use:

  • E-commerce flow testing
  • User journey validation
  • Complex workflow testing
  • Integration testing under load

⏱️ Testing - Rate Limiting Validation

Test API rate limiting behavior.

import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate } from 'k6/metrics';

const rateLimitHit = new Rate('rate_limit_hit');

export const options = {
  scenarios: {
    rate_limit_test: {
      executor: 'constant-arrival-rate',
      rate: 100,           // 100 requests per timeUnit
      timeUnit: '1s',
      duration: '1m',
      preAllocatedVUs: 50,
      maxVUs: 100,
    },
  },
};

export default function () {
  const res = http.get('https://api.example.com/data');

  check(res, {
    'success': (r) => r.status === 200,
    'rate limited': (r) => r.status === 429,
  });

  // Track rate limiting
  rateLimitHit.add(res.status === 429);

  if (res.status === 429) {
    const retryAfter = res.headers['Retry-After'] || 1;
    console.log(`Rate limited. Retry after ${retryAfter}s`);
  }

  sleep(0.1);
}

Expected Output:

$ k6 run rate-limit-test.js

INFO[0015] Rate limited. Retry after 60s                source=console
INFO[0018] Rate limited. Retry after 60s                source=console
INFO[0022] Rate limited. Retry after 60s                source=console

 success
 rate limited

     checks.........................: 100.00% 12000 0
     data_received..................: 2.4 MB  40 kB/s
     data_sent......................: 1.2 MB  20 kB/s
     http_req_blocked...............: avg=0.5ms    min=0s     med=0.4ms  max=15ms   p(90)=1ms    p(95)=1.5ms
     http_req_connecting............: avg=0.4ms    min=0s     med=0.3ms  max=12ms   p(90)=0.8ms  p(95)=1.2ms
     http_req_duration..............: avg=45ms     min=25ms   med=42ms   max=250ms  p(90)=68ms   p(95)=85ms
     http_req_failed................: 15.00% 900 5100
     http_req_receiving.............: avg=0.3ms    min=0.1ms  med=0.2ms  max=3ms    p(90)=0.5ms  p(95)=0.8ms
     http_req_sending...............: avg=0.2ms    min=0.1ms  med=0.1ms  max=2ms    p(90)=0.3ms  p(95)=0.4ms
     http_req_waiting...............: avg=44ms     min=24ms   med=41ms   max=248ms  p(90)=67ms   p(95)=84ms
     http_reqs......................: 6000    100/s
     iteration_duration.............: avg=145ms    min=125ms  med=142ms  max=350ms  p(90)=168ms  p(95)=185ms
     iterations.....................: 6000    100/s
     rate_limit_hit.................: 15.00% 900 5100
     vus............................: 50      min=50    max=100
     vus_max........................: 100     min=100   max=100

Rate limiting triggered at ~85 req/s (expected: 100/s)

When to use:

  • Validating rate limit configuration
  • Testing throttling mechanisms
  • API quota testing
  • DDoS protection validation

🔮 Testing - GraphQL Query Load Test

Load test GraphQL endpoints with complex queries.

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

export const options = {
  vus: 30,
  duration: '2m',
  thresholds: {
    http_req_duration: ['p(95)<800'],
  },
};

export default function () {
  const query = `
    query GetUserProfile($userId: ID!) {
      user(id: $userId) {
        id
        name
        email
        posts(limit: 10) {
          id
          title
          comments {
            id
            text
            author {
              name
            }
          }
        }
      }
    }
  `;

  const variables = {
    userId: Math.floor(Math.random() * 1000) + 1,
  };

  const payload = JSON.stringify({ query, variables });

  const params = {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN_HERE',
    },
  };

  const res = http.post('https://api.example.com/graphql', payload, params);

  check(res, {
    'query successful': (r) => r.status === 200,
    'no errors': (r) => !JSON.parse(r.body).errors,
    'has user data': (r) => JSON.parse(r.body).data.user !== null,
  });

  sleep(1);
}

Expected Output:

$ k6 run graphql-test.js

 query successful
 no errors
 has user data

     checks.........................: 100.00% 3600 0
     data_received..................: 7.2 MB  60 kB/s
     data_sent......................: 1.8 MB  15 kB/s
     http_req_blocked...............: avg=0.9ms    min=0s     med=0.6ms  max=22ms   p(90)=1.5ms  p(95)=2.2ms
     http_req_connecting............: avg=0.7ms    min=0s     med=0.5ms  max=18ms   p(90)=1.2ms  p(95)=1.8ms
 http_req_duration..............: avg=425ms    min=220ms  med=395ms  max=780ms  p(90)=590ms  p(95)=680ms
     http_req_failed................: 0.00% 0 1200
     http_req_receiving.............: avg=2.5ms    min=0.5ms  med=2ms    max=18ms   p(90)=4.5ms  p(95)=6ms
     http_req_sending...............: avg=0.5ms    min=0.1ms  med=0.4ms  max=6ms    p(90)=0.9ms  p(95)=1.3ms
     http_req_waiting...............: avg=422ms    min=218ms  med=393ms  max=778ms  p(90)=588ms  p(95)=678ms
     http_reqs......................: 1200    10/s
     iteration_duration.............: avg=1.42s    min=1.22s  med=1.39s  max=1.78s  p(90)=1.59s  p(95)=1.68s
     iterations.....................: 1200    10/s
     vus............................: 30      min=30    max=30
     vus_max........................: 30      min=30    max=30

 All thresholds passed

When to use:

  • GraphQL API load testing
  • Complex nested query testing
  • Resolver performance testing
  • N+1 query problem detection

📤 Testing - File Upload Performance

Test file upload endpoints with multipart data.

import http from 'k6/http';
import { check, sleep } from 'k6';
import { SharedArray } from 'k6/data';

const file = open('./test-file.pdf', 'b'); // Binary file

export const options = {
  vus: 10,
  duration: '1m',
  thresholds: {
    http_req_duration: ['p(95)<3000'], // Uploads can be slower
  },
};

export default function () {
  const formData = {
    file: http.file(file, 'test-file.pdf', 'application/pdf'),
    description: 'Test file upload',
    category: 'documents',
  };

  const res = http.post('https://api.example.com/upload', formData, {
    headers: {
      'Authorization': 'Bearer YOUR_TOKEN_HERE',
    },
  });

  check(res, {
    'upload successful': (r) => r.status === 201,
    'has file id': (r) => JSON.parse(r.body).fileId !== undefined,
    'upload time reasonable': (r) => r.timings.duration < 5000,
  });

  sleep(2);
}

Expected Output:

$ k6 run file-upload-test.js

 upload successful
 has file id
 upload time reasonable

     checks.........................: 100.00% 900 0
     data_received..................: 180 kB  3.0 kB/s
     data_sent......................: 30 MB   500 kB/s
     http_req_blocked...............: avg=1.5ms    min=0s      med=1ms    max=45ms   p(90)=3ms    p(95)=5ms
     http_req_connecting............: avg=1.2ms    min=0s      med=0.8ms  max=38ms   p(90)=2.5ms  p(95)=4ms
 http_req_duration..............: avg=1.85s    min=850ms   med=1.72s  max=2.95s  p(90)=2.45s  p(95)=2.68s
     http_req_failed................: 0.00% 0 300
     http_req_receiving.............: avg=0.8ms    min=0.2ms   med=0.6ms  max=8ms    p(90)=1.5ms  p(95)=2.2ms
     http_req_sending...............: avg=125ms    min=45ms    med=118ms  max=350ms  p(90)=188ms  p(95)=225ms
     http_req_waiting...............: avg=1.72s    min=795ms   med=1.59s  max=2.82s  p(90)=2.32s  p(95)=2.55s
     http_reqs......................: 300     5/s
     iteration_duration.............: avg=3.85s    min=2.85s   med=3.72s  max=4.95s  p(90)=4.45s  p(95)=4.68s
     iterations.....................: 300     5/s
     vus............................: 10      min=10    max=10
     vus_max........................: 10      min=10    max=10

 All thresholds passed

When to use:

  • Testing document upload endpoints
  • Image upload performance
  • Large file handling
  • Multipart form data testing

📊 Performance Metrics Guide

Understanding K6 output metrics:

Response Time Percentiles:

  • P50 (Median): 50% of requests faster than this
  • P90: 90% of requests faster than this
  • P95: 95% of requests faster than this - common SLA target
  • P99: 99% of requests faster than this - tail latency

Request Timing Breakdown:

  • http_req_duration: Total request time (waiting + receiving)
  • http_req_waiting: Time to first byte (TTFB)
  • http_req_receiving: Time to download response
  • http_req_sending: Time to send request
  • http_req_blocked: Time waiting for connection
  • http_req_connecting: TCP connection time

Success Metrics:

  • checks: Assertion pass rate
  • http_req_failed: HTTP error rate
  • http_reqs: Total requests per second

When to use different thresholds:

  • API endpoints: p(95) < 500ms
  • Database queries: p(95) < 200ms
  • File uploads: p(95) < 3000ms
  • Complex reports: p(95) < 2000ms