Comparing Permissive-Licensed OSS Load Testing Tools — k6 Alternatives and Use-Case Mapping
k6 ships a fast, lightweight runtime that lets you author scenarios in JavaScript, and over the past few years it has become a de facto OSS load testing tool. The catch is that the k6 core has been licensed under AGPL-3.0 since its Load Impact days, and after Grafana acquired k6 in 2021 and relicensed Grafana / Loki / Tempo from Apache 2.0 to AGPL-3.0, any case that involves redistribution or embedding into a SaaS now triggers a heavier legal review.
In practice, the common reading on Grafana’s community forum is that the typical “write a script and invoke k6” usage does not trip AGPL’s network use clause. But organizations that blanket-exclude AGPL in their internal license policy, or vendors that want to embed k6 inside the SaaS they ship to customers, end up needing the same answer: rebuild the load testing stack from tools that are exclusively Apache 2.0, MIT, or BSD.
This post lines up the OSS load testing tools that fall under permissive licenses, compares them on protocol coverage, scripting experience, resource efficiency, CI/CD and observability integrations, and protocol specialization, then maps each candidate to a workload.
Drawing the Line Between Permissive and Copyleft
In the Open Source Initiative classification, “permissive” includes Apache License 2.0, the MIT License, the BSD family, and the ISC License. None of them require disclosure for commercial use, modification, or redistribution.
By contrast, GPL and AGPL are strong copyleft licenses that propagate disclosure obligations to derivative works, while MPL 2.0 and LGPL are weak copyleft (file-level or library-link-level disclosure). The Business Source License (BSL) family is also showing up more often, which is a delayed-copyleft model that flips to copyleft after a fixed time period. Always verify the current LICENSE file in the upstream repository before relying on a tool’s licensing posture.
Lining up the major load testing tools by license category looks like this.
| Category | Tools |
|---|---|
| Permissive (in scope) | Locust, Gatling OSS, Apache JMeter, Goose, Taurus, Vegeta, oha, autocannon, plow, Fortio, ghz, h2load (nghttp2), Yandex.Tank (Apache 2.0) |
| Reference (the comparison baseline) | k6 (AGPL-3.0) |
A Quick Map by Use Case
The list of permissive options is long, so a use-case map up front saves time during selection.
flowchart LR
A[Broad protocol + scripted scenarios] --> A1[Gatling OSS]
A --> A2[Locust]
A --> A3[Goose]
B[Multi-protocol + legacy assets] --> B1[Apache JMeter]
C[High-efficiency HTTP CLI] --> C1[Vegeta]
C --> C2[oha]
C --> C3[plow]
D[Tight Node.js integration] --> D1[autocannon]
E[gRPC focus] --> E1[ghz]
F[Microservices / Service Mesh] --> F1[Fortio]
G[HTTP/2 + HTTP/3 deep stats] --> G1[h2load]
H[Multi-tool aggregation] --> H1[Taurus]
The big forks are: do you want to script a scenario, hammer an HTTP API from the CLI, exercise gRPC or a service mesh, or aggregate multiple tools? Each branch lands on a different tool. The sections below walk through the categories in order.
Code-First Frameworks — Gatling, Locust, Goose, JMeter
This is the slot that competes head-to-head with k6, where you want complex user flows, authentication, and data-driven scenarios authored as code.
Gatling OSS — Async Architecture and Polyglot DSLs
Gatling OSS is licensed under Apache License 2.0 and built on Scala / Akka / Netty, and it is the strongest all-around k6 alternative. A single DSL covers HTTP/1.1, HTTP/2, WebSocket, SSE (Server-Sent Events), gRPC, MQTT, and JMS, and scenarios can be written in Java, Kotlin, Scala, JavaScript, or TypeScript.
The architecture is fully asynchronous on top of the Akka actor model, where virtual users are messages instead of threads, so a single injector can sustain tens of thousands of concurrent VUs. The default HTML report ships interactive percentiles, RPS, and error breakdowns, and CI integration drops in naturally via Maven, Gradle, or sbt.
One caveat: the report rendering uses Highcharts under a separate Gatling-Highcharts License, not the core Apache 2.0. It is free as long as you stay within Gatling, but reusing the Highcharts code outside Gatling is not permitted. For most organizations this is a non-issue; if you need a strictly Apache-2.0-only stack, swap in a different reporter. OSS distributed execution is also light on official support, so scaling further usually means rolling your own setup with Kubernetes Helm or moving to Gatling Enterprise.
Locust — Python Flexibility and Built-in Distribution
Locust is licensed under the MIT License and lets you write test scenarios as plain Python code. You attach @task methods to a User class and invoke whatever Python client library you need, including Requests, so the cost of authoring scenarios is minimal.
Internally, Locust runs on gevent greenlets with event-driven concurrency. Even under the GIL (Global Interpreter Lock), this is efficient for I/O-bound load testing. The built-in master / worker distributed mode runs thousands to tens of thousands of VUs per worker and scales horizontally across nodes, and the official distributed-load-generation guide covers the typical implementation patterns.
The web UI shows real-time RPS and error rates, but the static reporting story is weaker than Gatling’s. For deeper observability, the Prometheus exporter or Grafana dashboards are the usual choices. It is the natural first choice for Python-heavy teams or scenarios with serious business logic.
Goose — Rust Efficiency and a Locust-Style API
Goose is licensed under Apache License 2.0 and builds on Rust and Tokio. It carries the same “scenarios as code” model as Locust but runs them on Rust’s async runtime. Scenarios are Cargo projects that depend on the Goose crate, and the official book advertises that Goose generates “at least 11x as much traffic as Locust per-CPU-core” (project-self benchmark, so confirm with a PoC in your environment).
Distribution is handled by Gaggle (manager / worker), but Gaggle support was temporarily removed in Goose 0.17.0 and is unavailable on current releases (0.16.4 is the last version that ships it). HTML, JSON, and CSV outputs are all there. Rust’s type safety and easy single-binary deployment are real wins. The trade-offs are: every scenario change goes through compilation, the ecosystem is smaller than Locust’s, and non-HTTP protocols are handled via record_custom_request rather than first-class support since the underlying client is Reqwest.
Apache JMeter — The Multi-Protocol Veteran
Apache JMeter is the original Apache 2.0 OSS load testing tool, with native support for HTTP / HTTPS, SOAP / REST, FTP, JDBC, LDAP, JMS, SMTP / POP3 / IMAP, TCP, and arbitrary Java objects. WebSocket, gRPC, and MQTT live in plugins from the JMeter Plugins ecosystem, which is still actively maintained.
The design is thread-per-user: one OS thread per virtual user. That is intuitive and easy to debug, but resource efficiency hits the usual sync-thread ceiling. On the same hardware, async tools like Gatling or Goose can sustain considerably more VUs. The standard production pattern is to author scripts in the GUI and run the actual load in CLI mode (-n -t test.jmx -l result.jtl -e -o report).
JMeter 5.6 improved the programmatic API, so you can assemble a test plan in Java or Kotlin without editing the .jmx XML directly. JMeter remains the strongest pick for organizations with existing JMX assets and any enterprise environment that needs JDBC, JMS, or other non-web protocols alongside HTTP.
Code-First Tool Comparison
| Aspect | Gatling OSS | Locust | Goose | Apache JMeter |
|---|---|---|---|---|
| License | Apache 2.0 | MIT | Apache 2.0 | Apache 2.0 |
| Language / runtime | Scala / Netty | Python / gevent | Rust / Tokio | Java / JVM |
| Scenario authoring | Java / Kotlin / Scala / JS / TS DSL | Plain Python | Rust (Cargo) | XML (GUI) / Groovy / Java DSL |
| Concurrency model | Actor model (async) | Greenlets (event-driven) | Async / multi-core | Thread-per-user |
| Major protocols | HTTP/1.1, HTTP/2, WebSocket, SSE, gRPC, MQTT, JMS | HTTP / HTTPS (anything via plugins) | HTTP / HTTPS (custom metrics) | HTTP, JDBC, LDAP, JMS, FTP, TCP, etc. |
| Distributed execution | Single injector in OSS | Built-in master / worker | Gaggle (master / worker) | Master / slave |
| Observability | Rich HTML report | Web UI, OTel, Prometheus exporter | HTML / JSON / CSV | HTML, Backend Listener (InfluxDB, Graphite) |
High-Efficiency HTTP CLI Tools
When you do not need complex flows and just want to push a single endpoint to its limits, lightweight single-binary tools are dramatically more efficient. They are also the easiest layer to drop into CI as a regression gate.
Vegeta — Constant RPS and Prometheus Export
Vegeta is MIT-licensed, written in Go, and focused on HTTP / HTTPS. Its design centers on holding a constant request rate, which sidesteps Coordinated Omission and makes it well-suited for SLO validation.
The CLI is composable in classic UNIX style (echo "GET https://example.com" | vegeta attack -rate=100 -duration=30s | vegeta report), and it ships a built-in Prometheus exporter along with JSON, CSV, and plot output. It also works as a Go library, which makes it easy to embed inside an internal load generator and run it on a steady cadence.
oha — A Modern Rust + TUI Option
oha is MIT-licensed, built on Rust / Tokio, and ships a CLI with a ratatui-based terminal UI for live histograms and latency trends. It supports HTTP/1.1, HTTP/2, and experimental HTTP/3, and --latency-correction provides Coordinated Omission correction.
It distributes as a single Rust binary via Homebrew and a GHCR container image, and it is on its way to becoming the go-to ad-hoc HTTP API benchmark.
plow — Real-Time Web UI in a Single Go Binary
plow is licensed under Apache License 2.0, built in Go on top of fasthttp, and ships a built-in real-time web UI on :18888. Because live RPS and latency distributions are visible in the browser, it works well when SREs and developers want to share results on the same screen during a load run.
autocannon — Tight Integration with Node.js Projects
autocannon is MIT-licensed and built on Node.js, and it is trivially installed alongside an existing Node project with npm i -D autocannon. It works as both a CLI and a JS API, with a Worker threads parallel mode. The README itself flags it as CPU-bound, so absolute throughput will trail the Go / Rust / C tools, and it is HTTP/1.1-centric. It shines when you want to keep the benchmark inside the Node ecosystem or have API authors run a quick benchmark per pull request.
CLI Tool Comparison
| Tool | Language | HTTP/2 | HTTP/3 | Observability / output | Notable |
|---|---|---|---|---|---|
| Vegeta | Go | Yes | No | Built-in Prometheus, JSON, plots | Constant RPS, UNIX pipes |
| oha | Rust | Yes | Experimental | TUI, JSON, CSV, SQLite | Single binary, latency correction |
| plow | Go | Yes | No | Real-time web UI | :18888 dashboard |
| autocannon | Node.js | No | No | JSON, HTML | npm-distributed, easy CI fit |
Protocol-Specialized Tools
ghz — The De Facto gRPC Benchmark
ghz is Apache License 2.0 Go focused on gRPC load testing. It dynamically dispatches calls from .proto or protoset files, so the server does not need a special test endpoint. Unary, client / server / bidirectional streaming are all covered.
Reports come in JSON, HTML, and CSV, and metrics export via Prometheus or InfluxDB line protocol, so wiring it into CI as a regression gate is straightforward. The runner package is also callable directly from Go programs for E2E test integration. For continuously testing gRPC microservices under a permissive-license constraint, it is essentially the only choice.
h2load — Deep Statistics for HTTP/2 and HTTP/3
h2load is the C++ benchmark bundled with the MIT-licensed nghttp2 library, supporting HTTP/1.1, HTTP/2, and HTTP/3 (QUIC). You get statistics down to the level of ALPN negotiation, HPACK compression efficiency, and stream flow control, which is invaluable for inspecting protocol-level behavior of HTTP/2 and HTTP/3.
Its scenario story is weak (header customization at most), but with --enable-http3 enabled at build time you can drive QUIC traffic directly, which still makes it the best choice for CDN and TLS stack validation.
Fortio — Microservices and Service Mesh
Fortio is Apache License 2.0 Go that began as the Istio project’s load generator and is now an independent repository. It covers HTTP / HTTPS, HTTP/2 (via gRPC), gRPC, TCP / UDP / echo / nc / proxy, and is designed to hold an exact QPS target.
Running fortio server boots both a web UI and a REST API, so result histograms, re-runs, and run-to-run comparisons happen entirely in the browser. The Docker image is under 6 MB, so it sidecars cleanly into Kubernetes pods and CI jobs. For SRE / Platform teams who need to validate Service Mesh behavior, gRPC, or TCP / UDP, it sits alongside ghz as a default pick.
Taurus — Aggregating Multiple Tools
Taurus is Apache 2.0 Python that wraps execution engines like JMeter, Gatling, Locust, Selenium, k6, Newman, ApacheBench, and Molotov under a unified YAML / JSON configuration.
execution:
- concurrency: 100
ramp-up: 1m
hold-for: 5m
scenario: quick-test
scenarios:
quick-test:
requests:
- http://example.com/api/v1/statusThe flags, thresholds, and report settings that used to be scattered across each underlying tool collapse into a single file. That is useful for organizations running several tools in parallel, or any team that wants to keep its JMeter assets but move to a more modern YAML-based configuration. One caveat: Taurus is Apache 2.0, but the underlying tools’ licenses still apply. Driving k6 through Taurus puts you back under AGPL. If you need a permissive-only stack, restrict the underlying engines to JMeter, Gatling, Locust, and similar permissive options.
Resource Efficiency and Real-World VU Capacity
Tool choice translates almost directly into infrastructure cost via “how many VUs can this hardware sustain?” Classic thread-per-user models and modern async / goroutine / lightweight-process models are far apart on memory.
| Tool | Architecture | Per-VU cost | Notes |
|---|---|---|---|
| Apache JMeter | Thread-per-user | About 1 MB (OS thread) | Heap tuning is mandatory |
| k6 (reference) | Goroutine | About 100 KB | Lightweight, but out of scope here (AGPL) |
| Gatling OSS | Actor model | Lightweight messages | 10K+ VUs from a single injector |
| Locust | gevent / greenlet | Tens to hundreds of KB | Scales horizontally via distributed mode |
| Goose | Rust async | Tens of KB | Multi-core, very efficient single process |
| Vegeta / oha / Fortio | Go / Rust runtime | Roughly tens of KB | Single-binary, light operations |
The exact numbers vary with benchmark conditions, so the only safe choice is a PoC on representative hardware. The following is a field heuristic rather than a sourced measurement, but as a rough mental model: “Gatling or Locust gets you several times more VUs per box than JMeter (roughly 2-5x in practice),” and “specialized CLI tools (Vegeta, oha, Fortio) sustain even higher RPS on the same hardware.” Use this lens first when deciding whether you actually need distributed execution across multiple machines.
CI/CD Integration and Quality Gates
Every major permissive-licensed tool is built with CI in mind, and they all support quality gates that fail the build when the result regresses.
- Gatling: scenarios use the Assertions DSL so you can fail the build on a 95th-percentile or error-rate breach via a non-zero exit code.
- Locust: by default the process exits with code 1 if any sample failed. For richer threshold checks, the official “Controlling the exit code” pattern is to hook the
quittingevent and overwriteenvironment.process_exit_codebased onfail_ratioor 95th-percentile latency.--headlessruns without the web UI for CI-friendly output. - Vegeta / oha / Fortio: parsing the JSON output and asserting thresholds with a one-liner is standard. Vegeta also exports Prometheus metrics natively, which can flow straight into SLO monitoring.
- ghz: dispatch a fixed load via
--rpsand--total, then pull latency or error rate out of the JSON report with jq for threshold checks.
GitHub Actions, GitLab CI/CD, and Jenkins all have ready templates, so per-PR runs or nightly batch runs are both straightforward to wire up depending on your release cadence.
Real Browser-Based User Load
If you want browser-based load testing with permissive licensing only, k6’s k6/browser is off the table because it inherits AGPL. The realistic alternative is running Playwright (Microsoft, Apache 2.0) or Puppeteer (Google, Apache 2.0) at scale via Kubernetes Job or platforms like Vercel Sandbox, and shipping the metrics into Prometheus yourself.
Browser load uses hundreds of MB of memory per VU, so the cost-effective design is a hybrid: protocol-level load with Locust or Gatling, plus a small number of browser scenarios for the user-facing journeys. If you need to roll your own Playwright-style assertion API, the Apache 2.0 grafana/k6-jslib-testing (a k6-specific JS library) is a useful reference for how that API can be implemented.
Choosing per Use Case
In practice, “which tool is strongest” matters less than “which one fits your team’s operations and protocol mix.” Here is the use-case-based summary.
- Picking a new organization-wide standard (replacing k6 with permissive-only): Gatling OSS is the lead candidate. A single DSL covers HTTP/2, WebSocket, gRPC, MQTT, and JMS, and you can write in Java, Kotlin, or TypeScript depending on your existing skills.
- Complex business-logic scenarios / Python team: Locust. The freedom of the Python library ecosystem and the built-in distributed mode are decisive.
- Rust-first teams that want compile-time safety / push a single process to its limit: Goose. Multi-core utilization plus the consistency of Cargo builds.
- Keep existing JMeter assets while mixing in JDBC, JMS, and other protocols: Apache JMeter. Still unrivaled on non-web protocol coverage.
- Lightweight HTTP API regression in CI: Vegeta (constant RPS) or oha (TUI and modern output). For Node.js projects, autocannon.
- gRPC microservices: ghz. Dynamic loading of
.protofiles is a clean fit. - Service mesh and SRE-style cross-protocol checks (TCP / UDP / gRPC): Fortio. Strong affinity with the Istio ecosystem.
- Deep HTTP/2 and HTTP/3 protocol inspection: h2load. Useful for CDN and TLS stack validation.
- Aggregating multiple tools under a unified interface: Taurus. Watch for license inheritance from the underlying engines.
Once you stop framing this as “find a single k6 alternative,” the permissive-license catalog has rich answers per workload. A multi-layered setup (Vegeta or oha for HTTP API regression, Gatling or Locust for complex scenarios, ghz for gRPC) typically lowers both the licensing burden and the operational cost. As always, verify the current LICENSE on the upstream repository, and run a PoC on representative hardware before committing.
That’s all from someone comparing permissive-licensed OSS load testing tools as k6 alternatives. From the gemba.