Test Tools · Performance Testing

Gatling

High-performance load testing in Scala. Simulates tens of thousands of concurrent users with elegant DSL and detailed reports.

Overview

Gatling, created in 2011, is a high-performance load testing tool written in Scala. It uses an elegant domain-specific language (DSL) for writing test scenarios and can simulate tens of thousands of concurrent virtual users from a single machine. Gatling is particularly strong for web application load testing, including complex user journeys with authentication, session management, and dynamic data.

Gatling generates beautiful HTML reports with detailed latency percentiles, response time distributions, and error analysis. It is the tool of choice for teams that need serious load generation and professional reporting.

What it's used for

Gatling is the right choice when:

  • High-concurrency testing needed: Simulate 50,000+ concurrent users from a single machine.
  • Complex web scenarios: Test multi-step user journeys with authentication, sessions, and state.
  • Professional reporting required: Executive-ready HTML reports with detailed metrics.
  • Scala/Java team: Tests are Scala code, fitting naturally into JVM-based projects.

Pros & Cons

Pros

  • Extremely efficient resource usage — simulates more users per machine than JMeter
  • Beautiful, detailed HTML reports
  • Elegant Scala DSL for scenario definition
  • Strong CI/CD integration with Maven, Gradle, and Jenkins
  • Active community and commercial support (Gatling Enterprise)

Cons

  • Scala DSL has a learning curve for non-Scala developers
  • No GUI for test creation — everything is code
  • Less intuitive for API-only testing than k6
  • Distributed testing requires Gatling Enterprise or custom orchestration
  • Smaller community than JMeter

Platforms & Integrations

Gatling runs on Windows, macOS, and Linux. It requires Java 11+ and is typically managed via Maven or Gradle. Gatling Enterprise adds cloud execution and distributed load generation.

Windows macOS Linux Scala Java Kotlin Maven Gradle Jenkins GitHub Actions GitLab CI Azure DevOps Docker AWS GCP Azure

Pricing

TierCostIncludes
Open SourceFreeFull framework, local execution, HTML reports
Gatling EnterpriseCustomCloud execution, distributed load, advanced analytics, support

NZ Context

Gatling is used by NZ enterprise teams with high-traffic web applications — particularly in financial services, government, and large-scale e-commerce where JVM stacks are common. NZ organisations running Spring Boot or Kotlin backends find Gatling a natural fit because load simulations can live in the same Gradle or Maven build as the application code. Government agencies and large retailers have leaned on Gatling's detailed latency percentile reports when presenting performance evidence to architecture review boards. However, k6 is gaining ground among NZ SaaS startups due to its JavaScript syntax and lower onboarding cost for teams that don't have Scala or JVM expertise.

Alternatives

  • k6 — JavaScript-based. Better DX for non-Scala teams.
  • JMeter — GUI-based. Larger community and more plugins.
  • Locust — Python-based with distributed load testing. Better for Python teams.

When to choose Gatling

A quick decision guide for NZ teams evaluating performance testing options.

Choose Gatling when… Choose something else when… Combine with…
Your team is on the JVM stack — Spring Boot, Kotlin, or Scala — and load test scripts should live alongside application code in the same repo and build pipeline. Your team writes JavaScript end to end. k6 will feel native, ships in a single binary, and keeps JavaScript engineers in the tool without a Scala ramp-up. Grafana + InfluxDB for live dashboards during a load run, since Gatling’s own HTML report is post-run only.
You need to simulate 10,000–100,000 concurrent virtual users from a single machine without hiring a cluster. Gatling’s actor model uses far less RAM per VU than JMeter threads. Your test plan is protocol-heavy — SOAP, FTP, JDBC, or custom TCP. JMeter’s plugin ecosystem covers protocols Gatling does not support out of the box. WireMock or Mockoon to stub downstream APIs so load tests hit realistic latency without hammering third-party rate limits.
Stakeholders want polished, shareable HTML reports straight out of CI — Gatling’s built-in report shows latency percentiles, response time distributions, and error timelines with no extra setup. Your team is new to performance testing entirely. Locust’s Python syntax and browser-based UI lower the barrier to a first working test; Scala DSL can wait until the team has the basics. Playwright for browser-level smoke tests at low concurrency — Gatling handles the HTTP flood while Playwright confirms real-browser rendering still works under load.
You need assertions baked into CI that fail the build automatically when p95 latency breaches a threshold — Gatling’s assertions API handles this natively without post-processing scripts. You are primarily testing GraphQL APIs with variable query depth. k6 has better first-class GraphQL support and the scripting model maps more naturally to query parameterisation. Gatling Enterprise (paid) or a Kubernetes job runner for distributed load across multiple injectors when a single machine cannot generate enough throughput for your peak targets.

What I would do

Practitioner judgment on tool adoption, team onboarding, and when to swap.

If…
I was on the QA team at CloudBooks NZ, where the tax filing platform handles a sharp concurrency spike every year at the 31 March balance-date deadline, and we needed to prove the system could absorb 40,000 simultaneous API calls without latency climbing above 2 seconds at p95.
I would…
Wire Gatling into the existing Gradle build so load simulations live next to unit tests and run on the same Jenkins pipeline. I would write a realistic scenario that follows the actual filing journey — authenticate, fetch client list, submit return, poll for acknowledgement — not just hammer a single endpoint. Then set a hard Gatling assertion at p95 ≤ 2 s and p99 ≤ 5 s so the build fails automatically if performance regresses between releases. The HTML report goes into the CI artefact store so any team member can review it without SSH access to a load box.
If…
I was leading performance testing at CityTransit, whose AT Mobile app must survive the Monday morning rush with tens of thousands of passengers checking real-time arrivals, and the backend team was already running Spring Boot microservices on Java 17.
I would…
Start with the Gatling Kotlin DSL (available since Gatling 3.7) rather than Scala — Kotlin is already in the team’s comfort zone and removes the main adoption objection. I would build two simulation classes: one for steady-state background traffic at 5,000 users, one for a ramp spike to 30,000 users over 90 seconds mirroring Monday peak. I would also hook Grafana + InfluxDB to the Gatling metrics output so operations staff can watch the run live on the NOC screen rather than waiting for the post-run HTML report. If the spike simulation repeatedly saturates the injector machine before reaching target VU, that’s the trigger to evaluate Gatling Enterprise for multi-node injection.
If…
I joined a team at ListRight that had inherited a legacy JMeter suite of 200 test plans — many of them recorded scripts with hardcoded session tokens and no parameterisation — and we were hitting the limit of what a single JMeter node could generate reliably.
I would…
Not do a big-bang migration. I would pick the three highest-value scenarios — search, listing view, and checkout — rewrite those in Gatling as a pilot, and run both tools in parallel for one sprint to validate the Gatling numbers match JMeter’s at equivalent VU counts. Once the team trusts the parity, migrate one area at a time and retire the JMeter equivalents. Trying to convert all 200 scripts at once is how migrations stall permanently. The parallel-run validation step is non-negotiable: stakeholders will not believe the new numbers unless you can show they match the old ones first.

The bottom line: Gatling earns its place when you need code-first load tests that fail the build automatically — but the Scala DSL is a real adoption cost, so always run a Kotlin DSL spike first to confirm the team can own the tests long-term without you.

Interview questions

Questions you are likely to get if you list Gatling on your CV — with what interviewers are really testing for.

What is the difference between Gatling’s virtual user model and JMeter’s thread-based model, and why does it matter for high-concurrency tests?

What they’re really testing: Whether you understand why Gatling can simulate far more users per machine than JMeter, or whether you just know how to run scripts without understanding the underlying architecture.

Strong answer covers: Gatling uses an actor/coroutine model (Akka under the hood) where each virtual user is a lightweight message — thousands share the same OS thread pool; JMeter gives each VU a full Java thread, which caps out at a few thousand before GC and context-switching dominate. Mention the practical implication: on a single 8-core CI runner (common in NZ teams using GitHub Actions), Gatling can sustain 20,000 VUs where JMeter would struggle beyond 2,000.

When would you choose Gatling over k6, and when would you choose k6 over Gatling?

What they’re really testing: Whether you can articulate tool trade-offs objectively rather than defaulting to whichever tool you learnt first.

Strong answer covers: Gatling wins when the team is already on the JVM (Spring Boot, Kotlin) and wants load tests in the same Gradle/Maven build, or when stakeholders need polished post-run HTML reports with latency percentiles out of the box. k6 wins when the team writes JavaScript end to end, needs built-in Grafana Cloud integration, or is primarily hitting GraphQL APIs. In an NZ context, many Wellington government shops (Benefits NZ, Revenue NZ) have Java stacks that suit Gatling, while Auckland SaaS startups often lean k6 for its lower entry cost.

You’re joining the platform team at CloudBooks NZ. Their Kotlin-based tax filing API needs to handle 40,000 concurrent users at the 31 March balance-date deadline without p95 latency exceeding 2 seconds. How would you design and integrate the Gatling test suite?

What they’re really testing: Whether you can translate a business SLA into a realistic Gatling simulation — not just a hammer test — and whether you understand CI integration and threshold assertions.

Strong answer covers: Use the Gatling Kotlin DSL (3.7+) so simulations sit naturally alongside application code in Gradle; model the actual filing journey (authenticate → fetch client list → submit return → poll acknowledgement) rather than a single-endpoint flood; add assertions().forAll().responseTime().percentile(95).lt(2000) to hard-fail CI on regression; publish the HTML report as a Jenkins/GitHub Actions artefact; and mention the need to stub or rate-limit downstream Revenue NZ gateway calls during the run so CloudBooks doesn’t inadvertently DoS a government service.

Your Gatling simulations pass on your local machine but consistently time out in CI. The same scenario, same VU count. What do you investigate first?

What they’re really testing: Systematic debugging instinct and awareness of the environmental differences between developer laptops and CI runners that affect load test results.

Strong answer covers: Check CI runner resources first — shared GitHub Actions runners or GitLab shared runners typically have 2 vCPUs and 7 GB RAM, whereas your laptop may have 16 cores; Gatling can exhaust the injector before the target service is stressed. Then check network: CI runners often egress through a NAT gateway with limited connection pool, causing TCP connection errors that look like server timeouts. Also verify that CI isn’t running against a scaled-down staging environment. Fix by either reducing VU count in CI (use a smoke-level simulation) or running Gatling on a dedicated large runner, and add the connectionTimeout and readTimeout protocol settings to surface true connection vs. response errors separately.

How would you structure a Gatling test suite for a large e-commerce platform so it scales as the team and product grow, without becoming a maintenance burden?

What they’re really testing: Architecture thinking — whether you’ve thought beyond a single script to something a team of engineers can own and evolve.

Strong answer covers: Separate scenarios (user journeys: browse, search, checkout) from simulations (how many VUs, what ramp shape) so the same journey can be reused in a smoke simulation (50 VUs, 2 min) and a soak simulation (2,000 VUs, 8 hours); use feeder files for test data (product IDs, user credentials) to keep scripts environment-agnostic; store thresholds in a config object rather than scattered through assertion calls; and for NZ teams on Gradle, publish simulations as a separate Gradle subproject so performance engineers can run them independently of the app build.

Learn more