# k6 vs JMeter: The Same 100-User Load Test, Side by Side

Most "JMeter vs k6" articles compare feature lists. I wanted to see the difference in the files themselves, so I wrote the same load test twice: 100 virtual users hitting one endpoint for 30 seconds, once as a k6 script and once as a JMeter plan. Both files, plus the tiny demo app they hit, are in a public repo so you can run them yourself: [zainbasra/aitg-test-kits](https://github.com/zainbasra/aitg-test-kits).

A quick honesty note before any numbers: the server and the load generator ran on the same machine, against a trivial JSON endpoint. That shows how each tool behaves. It is not a capacity benchmark of anything.

## The test

- **Target:** `GET http://127.0.0.1:3000/users` on a small Node.js demo server (no dependencies).
- **Load:** 100 virtual users, 30 seconds, 1 second of think time between requests.
- **Pass rule:** 95% of requests faster than 200 ms.

## Version 1: k6 (a JavaScript file)

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

export const options = {
  vus: 100,
  duration: '30s',
  thresholds: { http_req_duration: ['p(95)<200'] },
};

export default function () {
  const res = http.get('http://127.0.0.1:3000/users');
  check(res, { 'status is 200': (r) => r.status === 200 });
  sleep(1);
}
```

That's the whole test. The load profile, the assertion and the pass/fail rule live in one file you can review in a pull request. Run it with `k6 run k6-users.js`. If the threshold fails, k6 exits with a non-zero code, so your CI job fails without any extra plugin.

## Version 2: JMeter (an XML test plan)

The same load in JMeter is a `.jmx` file: a Thread Group with 100 threads, a 30-second duration and a 1-second ramp-up, an HTTP Request sampler for `/users` on port 3000, and a Constant Timer of 1,000 ms for think time. You normally build it in the JMeter GUI, then run it headless:

```bash
jmeter -n -t jmeter-users.jmx -l result.jtl
```

The plan works fine, but it's XML generated by a GUI. A reviewer can't easily see what changed between two versions, and the 200 ms pass rule needs an extra assertion or a post-processing step in your pipeline rather than a single line.

## Results (10 Nov 2026, one Windows PC, everything local)

| | k6 2.3.0 | JMeter 5.6.3 |
|---|---|---|
| Requests | 3,000 | 2,874 |
| Errors | 0 | 0 |
| Average response | 0.99 ms | 2 ms |
| Max response | 24.54 ms | 98 ms |
| Throughput | ~99.8 req/s | ~95.6 req/s |

Both tools handled this load without errors, and both landed close to the expected 100 requests per second for 100 users with 1 second of think time. The small gaps come from how each tool schedules threads and counts samples. On a toy endpoint like this, they say nothing about which tool is "faster" for your system. Your numbers will differ with hardware, versions and background load.

## The k6 typo worth knowing about

The repo includes a second k6 script with one change: the threshold is written `p95<200` instead of `p(95)<200`.

I re-ran it today with k6 2.3.0. k6 refuses to start the test at all:

```text
level=error msg="failed parsing threshold expression's \"p95<200\" left hand side; reason: failed parsing method from expression"
```

and exits with **code 104**. The good news is that it fails loudly instead of silently ignoring the rule. The catch: in CI this looks like a broken pipeline, not a failed performance check, so it's worth knowing what exit code 104 means before you go hunting through your app for a regression. The correct syntax wraps the percentile in brackets: `p(95)`, `p(99)`, `avg`, `max`.

## So which should you learn?

- **k6** if your tests should live in Git next to the code, run in CI on every merge and be reviewed like any other code. It suits developers and SDETs who are comfortable with JavaScript.
- **JMeter** if you need its very wide protocol support and plugin ecosystem, your team prefers a GUI, or you're joining a company with years of existing `.jmx` plans. It's still everywhere in enterprise QA.
- **Both** is a realistic answer for an SDET: k6 for new, code-first tests; enough JMeter to maintain what already exists.

The full comparison, covering scripting, CI/CD, resource use, protocol support, AI-assisted scripting and what job postings ask for, is on my site: **[JMeter vs k6 2026: Which Should You Learn as an SDET?](https://aitestingguide.com/jmeter-vs-k6/)**

Have you moved a JMeter suite to k6, or the other way around? I'd like to hear what made the switch worth it.

