Gatling Performance Testing Interview Questions 2026 — Async Non-Blocking Akka Engine Architecture, Scala DSL vs Java DSL Design, Gatling vs k6 vs JMeter Comparative Analysis, Simulation Setup with Injection Profiles (Open vs Closed Workload Models), Checks and Assertions for Response Validation, Gatling HTML Reports and Real-Time Metrics Dashboard, CI/CD Integration with Maven/Gradle and Jenkins/GitHub Actions, Feeders and Test Data Strategies for Realistic Load Scenarios, and How to Answer Performance Testing Questions That Target Gatling-Specific Knowledge in Senior SDET Panels
The complete Gatling performance testing interview guide for 2026 — covering the Scala-based load testing tool that Java/Scala shops use for high-throughput performance engineering. Covers Gatling's async non-blocking architecture powered by the Akka actor engine, the expressive Scala DSL for simulation scripting, a detailed Gatling vs k6 vs JMeter comparison across architecture, throughput, and developer experience, simulation setup with open vs closed workload injection profiles, checks and assertions for validating HTTP responses under load, Gatling's HTML reports and real-time metrics, CI/CD integration with Maven/Gradle build tools, feeder strategies for injecting realistic test data, and Scala/Java code examples of production-grade Gatling simulations. Built from Mitchell's 20 years of SDET interview panels at HMRC, MoD, Nationwide, and Accenture — where performance testing questions now routinely probe Gatling alongside k6 and JMeter.
Published 19 May 2026 • By Mitchell Agoma
You've prepared for k6. You can explain JMeter's thread-based architecture. You're ready to discuss percentile response times, ramp-up patterns, and how to identify bottlenecks from a CPU flame graph. Then the interviewer leans forward and says: "Our backend team uses Gatling — walk me through how you'd design a performance test for a Scala microservice handling 10,000 concurrent orders per minute. And while you're at it, explain why Gatling uses Akka instead of threads, and when you'd pick Gatling over k6 or JMeter." If your honest answer is "I know Gatling exists but I've mostly used k6 or JMeter," you're not alone — but in 2026, that gap is costing candidates offers at the senior and lead levels. Gatling has become the default performance testing tool in Java and Scala shops precisely because its architecture — an async, non-blocking, message-driven engine built on Akka — lets a single machine simulate tens of thousands of concurrent users without the thread-per-user overhead that limits JMeter or the JavaScript event-loop ceiling that constrains k6's maximum throughput on a single node. Interview panels now expect senior SDETs to understand all three major performance testing tools — not just pick one and call it done.
This guide covers every Gatling-specific question senior SDET panels are asking in 2026 — from the Akka architecture that makes Gatling unique, to the Scala DSL that powers its simulations, to the injection profiles and assertion DSL that turn load scripts into rigorous performance tests, to the CI/CD integration patterns that put Gatling in your pipeline. Every section maps to real interview questions Mitchell's panels have asked. And every code example is production-grade Scala — the kind you might be asked to whiteboard or critique. If you're interviewing at a company where the backend runs on the JVM — banks, fintechs, enterprise platforms, government systems — Gatling questions are coming. The SDET Interview Coach iOS app includes a dedicated Performance Testing topic that covers Gatling, k6, and JMeter — with mock interview questions scored across technical accuracy, completeness, and communication. Download it and practise the exact Gatling questions panels ask before you walk into the room.
Gatling Architecture — Async Non-Blocking Akka Engine (The Question That Separates Engineers From Scripters)
When a panel asks "how does Gatling work under the hood?" they are not asking you to describe the DSL syntax. They are testing whether you understand the architectural decision that defines Gatling's entire performance profile — and separates it from every other load testing tool. The answer centres on three words: Akka Actor Model.
The Akka Actor Engine — Why Gatling Doesn't Use Threads Per User
JMeter creates one thread per virtual user. A test simulating 10,000 concurrent users needs 10,000 threads — which consumes gigabytes of memory from thread stacks alone, triggers context-switching overhead that limits throughput, and hits OS-level thread limits long before generating realistic load. k6 uses a single-threaded JavaScript event loop with a configurable number of VUs — more efficient than threads, but still bound by the single-thread ceiling of the V8 engine for coordination. Gatling takes a fundamentally different approach: every virtual user is an Akka actor — a lightweight, message-driven computation unit that consumes roughly 300 bytes of memory (compared to 1MB+ for a JVM thread). The Gatling engine can run tens of thousands of concurrent actors on a single machine because actors share a small thread pool (typically CPU cores × 2) and the Akka dispatcher schedules actors on those threads non-blockingly. When an actor issues an HTTP request, it doesn't block a thread waiting for the response — it registers a callback and releases the thread for other actors. This is the architectural difference that lets Gatling achieve higher throughput per machine than either JMeter or k6.
The interview answer that scores highest: "Gatling uses the Akka actor model to virtualise users as lightweight messages rather than heavyweight threads. Each virtual user is an actor — roughly 300 bytes of memory — scheduled on a small thread pool by the Akka dispatcher. HTTP requests are non-blocking: an actor sends a request and releases its thread until the response arrives, allowing the same thread pool to serve thousands of concurrent actors. This is architecturally equivalent to how modern reactive web frameworks like Akka HTTP and Spring WebFlux work — which means Gatling's engine tests your application the same way your application serves real users. JMeter's thread-per-user model caps at a few thousand users per machine before thread overhead dominates. k6's event-loop model is more efficient than JMeter but still serialises user coordination through a single thread. Gatling's actor model scales to tens of thousands of concurrent users on commodity hardware — and because the architecture mirrors reactive JVM applications, the load you generate is architecturally realistic."
The Simulation Lifecycle — From Scenario Definition to Report Generation
A Gatling simulation goes through a well-defined lifecycle that interviewers expect you to understand: 1. Simulation Compilation: Gatling simulations are Scala classes compiled by the Scala compiler — not interpreted scripts. This means you get compile-time type checking on your simulation code. A typo in a HTTP status code assertion fails at compile time, not 30 minutes into a load test. 2. Scenario Instantiation: The scenario (a sequence of HTTP requests, pauses, loops, and conditional branches) is turned into a chain of Akka actors representing virtual users. 3. Injection: The injection profile determines how those actors are created over time — ramp-up patterns, constant rates, spikes, or custom schedules. 4. Execution: Actors execute their scenario chains, sending HTTP requests through Gatling's async HTTP client (backed by Netty for non-blocking I/O). Every request is timed: connection time, time-to-first-byte, time-to-last-byte. 5. Assertion Evaluation: Checks and assertions run in real-time on the response stream. Failed checks are logged with the full request/response context for debugging. 6. Report Generation: When the simulation completes, Gatling generates a self-contained HTML report with response time percentiles, throughput graphs, active user timelines, and request distribution analysis — no external reporting tools required.
Here's a minimal Gatling simulation that demonstrates the core architecture — this is the kind of code you might be asked to explain or critique in an interview:
// OrderServiceSimulation.scala — Minimal Gatling simulation
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class OrderServiceSimulation extends Simulation {
// HTTP protocol configuration — base URL, headers, connection pool
val httpProtocol = http
.baseUrl("https://api.orderservice.com")
.acceptHeader("application/json")
.contentTypeHeader("application/json")
.userAgentHeader("Gatling/3.12")
.shareConnections // Connection pooling for efficiency
// Scenario: what each virtual user does
val scn = scenario("Order Checkout Flow")
.exec(
http("Browse Products")
.get("/api/products?category=electronics")
.check(status.is(200))
)
.pause(2.seconds) // Think time
.exec(
http("Add to Cart")
.post("/api/cart/items")
.body(StringBody("""{"productId":"prod-123","quantity":1}"""))
.check(status.is(201))
)
.pause(1.second)
.exec(
http("Checkout")
.post("/api/orders")
.body(StringBody("""{"cartId":"$${cartId}","paymentMethod":"card"}"""))
.check(status.is(201))
)
// Injection profile and assertions
setUp(
scn.inject(
rampUsers(100).during(30.seconds), // Ramp to 100 users
constantUsersPerSec(20).during(60.seconds) // Hold at 20 users/sec
)
).protocols(httpProtocol)
.assertions(
global.responseTime.percentile(95).lt(500), // p95 < 500ms
global.responseTime.percentile(99).lt(1000), // p99 < 1s
global.successfulRequests.percent.gt(99) // > 99% success
)
}
This simulation reveals the architectural pattern: the scenario is a declarative chain of HTTP requests with built-in assertions (checks), the injection profile is separated from the scenario logic, and the assertions are global, evaluated across all users. This separation of concerns — scenario logic, load profile, and success criteria — is what makes Gatling simulations maintainable at scale and is exactly the pattern interviewers want you to recognise.
Gatling vs k6 vs JMeter — The Comparative Analysis Every Panel Expects
The performance testing landscape in 2026 has three dominant tools — and senior SDET panels expect you to understand the architectural trade-offs between all three. Not to evangelise for one. To demonstrate that you can match the tool to the context. Here's the comparison interviewers test for:
Gatling — JVM-Native, High-Throughput, Scala DSL
Architecture: Akka actors on the JVM. Non-blocking async HTTP via Netty. Compile-time checked Scala code. Throughput ceiling: Highest per-machine of the three — tens of thousands of concurrent users on a single instance thanks to the actor model and non-blocking I/O. Language: Scala DSL (primary) with Java DSL available but less ergonomic. This is Gatling's biggest adoption barrier — Scala expertise is rarer than JavaScript or Java. Protocol support: HTTP (first-class), WebSocket, JMS, MQTT, gRPC (via community plugin). Reporting: Self-contained HTML report generated after every run — response time percentiles, throughput graphs, active users over time, request distribution. No external dashboard required. Graphite/InfluxDB integration for real-time dashboards. CI/CD: Maven plugin, Gradle plugin, sbt integration. Runs as a JVM process — no separate daemon or service. Best for: JVM shops (Java, Scala, Kotlin) where the backend language matches the test language, high-throughput microservice testing, and teams that value compile-time safety in performance tests.
k6 — Developer-Friendly, JavaScript/Go, Cloud-Native
Architecture: Go-based engine executing JavaScript test scripts via the goja JS runtime. Each VU runs on a separate goroutine (Go's lightweight thread equivalent). Go's scheduler handles concurrency — efficient, but coordination between VUs requires explicit orchestration. Throughput ceiling: Lower than Gatling per machine — the JavaScript runtime adds overhead, and the single-threaded event-loop coordination limits peak throughput. However, k6's cloud execution (Grafana Cloud) can distribute load across many machines, offsetting the per-node limitation. Language: JavaScript — the lowest adoption barrier. Any frontend or Node.js developer can write k6 tests. Protocol support: HTTP (first-class), WebSocket, gRPC (native), browser (xk6-browser for frontend performance). Reporting: Built-in summary to stdout, JSON output for external processing, Grafana Cloud for dashboards and trend analysis. No self-contained HTML report out of the box. CI/CD: Single binary, runs anywhere. Native GitHub Action. Best for: JavaScript/TypeScript teams, organisations already using Grafana for observability, developer-centric performance testing where lowering the barrier to entry matters more than maximum per-machine throughput.
JMeter — Legacy Workhorse, GUI Editor, Plugin Ecosystem
Architecture: Thread-per-user model — 1,000 users = 1,000 threads. This is the oldest architecture and the most resource-intensive. JMeter can run in distributed mode (master + slaves) to aggregate load across machines — compensating for the per-machine thread ceiling. Throughput ceiling: Lowest per-machine of the three. A typical JMeter instance handles 500-2,000 concurrent users before thread overhead dominates. Distributed mode can scale higher but adds infrastructure complexity. Language: GUI-driven test plan editor with XML persistence. Scripting via Beanshell, Groovy, or JSR223. No native DSL — test plans are configured, not coded. Protocol support: Broadest of the three — HTTP, JDBC, FTP, LDAP, JMS, SOAP, TCP, and dozens more via plugins. This is JMeter's strongest differentiator: it can test virtually any protocol. Reporting: Requires plugin configuration for dashboards. Built-in HTML report dashboard (since JMeter 3.0) but less polished than Gatling's. CI/CD: CLI mode (jmeter -n -t test.jmx). Jenkins Performance Plugin for trend analysis. Heavier CI footprint than k6 or Gatling. Best for: Legacy systems already invested in JMeter, mixed-protocol testing (HTTP + JDBC + JMS in one test), organisations with non-developer QA teams who prefer GUI-based test authoring, and protocols that Gatling and k6 don't support.
The interview comparison framework: "I select the performance testing tool based on the team's language ecosystem and the throughput requirements. For JVM shops with Scala or Java expertise — fintech, enterprise platforms, government systems — Gatling gives the highest per-machine throughput and compile-time safety through the Scala DSL. For JavaScript/TypeScript teams already using Grafana for observability — platform engineering, DevOps-heavy organisations — k6 provides the lowest adoption barrier and native Grafana Cloud integration. For organisations with existing JMeter investment, mixed-protocol requirements, or non-developer QA teams — I'd evaluate whether JMeter meets their needs before proposing a migration. The tool matters less than the testing methodology — the load model, the success criteria, and the bottleneck analysis process are framework-agnostic. What changes is the implementation ergonomics and the per-machine throughput ceiling." For a deeper dive on k6, see our k6 Performance Testing Interview Questions guide.
Injection Profiles — Open vs Closed Workload Models (The Question That Tests Load Modelling Competence)
One of the most nuanced Gatling interview questions is: "Explain the difference between open and closed workload models, and when you'd use each." This question tests whether you understand load modelling at the conceptual level — not just the Gatling DSL syntax.
Closed Workload Model — Users Wait Before Making the Next Request
In a closed model, a fixed pool of virtual users repeatedly executes a scenario. When a user finishes one iteration (completes all requests in the scenario), they immediately start the next iteration — or pause for a defined think time, then start again. The key characteristic: the arrival rate of new requests depends on the system's response time. If the system slows down, virtual users take longer to complete their scenarios, and the request rate drops. This creates a self-throttling effect — the load naturally backs off when the system is stressed. Closed systems model user-facing web applications where real users complete an action, read the response, and then decide what to do next. Gatling's closed-model injectors: atOnceUsers(n) (inject n users all at once), rampUsers(n).during(d) (linearly ramp to n users over duration d), constantConcurrentUsers(n).during(d) (maintain n concurrent users for duration d — adding more when users finish), and rampConcurrentUsers(from).to(to).during(d) (ramp concurrent users from one level to another).
When to use: Testing web applications where users navigate through pages. Load testing a checkout flow where each user goes through browse → cart → checkout. Capacity testing — how many concurrent users can the system handle before response times degrade beyond your SLA.
Open Workload Model — Requests Arrive at a Fixed Rate
In an open model, new users are injected at a fixed rate per second, regardless of how long existing users take to complete their scenarios. If the system slows down, the injection rate stays constant — which means the number of concurrent users in the system increases unboundedly as response times degrade. This models API services, message queues, and backend systems where requests arrive at a fixed rate from upstream services, and the system must process them regardless of how long each one takes. Gatling's open-model injectors: constantUsersPerSec(rate).during(d) (inject n users per second for duration d), rampUsersPerSec(from).to(to).during(d) (ramp from one rate to another), stressPeakUsers(peak).during(p).randomized (sudden spike to peak users), and nothingFor(d) / incrementUsersPerSec(step).eachLevelLasting(d) for staircase load patterns.
When to use: Testing API endpoints that serve upstream microservices. Load testing a message-processing system where events arrive at a steady rate. Stress testing — what happens when the system receives more requests than it can handle? Open models reveal the breaking point because the load doesn't self-throttle.
Hybrid injection profiles — the advanced answer: In production, most systems experience a mix of open and closed workloads. An e-commerce site has closed-model user flows (browse → checkout) alongside open-model API traffic (inventory service receiving queries from multiple frontends). Gatling supports hybrid injection by combining injectors in the setUp() block. The strongest interview answer acknowledges this: "I use closed models for user-facing flows where think times matter, open models for API endpoints where arrival rates are independent of response times, and hybrid profiles for systems that serve both. The injection model I choose depends on what question I'm trying to answer — capacity (closed model: how many concurrent users?) or throughput (open model: how many requests per second?)."
// Hybrid injection profile — closed + open in one simulation
setUp(
// Closed: ramp real user flow to 500 concurrent users
userScenario.inject(
rampConcurrentUsers(0).to(500).during(5.minutes)
),
// Open: constant API traffic at 200 req/s throughout
apiScenario.inject(
constantUsersPerSec(200).during(10.minutes)
)
).protocols(httpProtocol)
Checks and Assertions — Validating Behaviour Under Load
A load test that doesn't validate responses isn't a test — it's a traffic generator. Gatling's check and assertion system transforms load generation into rigorous performance testing. Interview panels test this distinction: they want to know that you don't just generate load — you validate that the system behaves correctly under that load.
Checks — Per-Request Validation
Checks are attached to individual HTTP requests and validate the response as it arrives. They execute in the hot path — inside the virtual user's scenario chain — and a failed check is recorded immediately with the full request/response context. Key check types: status.is(200) — validate HTTP status code (the most common check — interviewers expect you to use this on every request); responseTimeInMillis.lt(500) — validate that this specific request responded within a time budget; jsonPath("$.orderId").exists — validate that the JSON response contains a required field (and optionally save it to the session for use in subsequent requests via .saveAs("orderId")); bodyString.transform(_.length).gt(0) — validate that the response body is non-empty; cssSelector(".success-message").exists — validate HTML responses contain expected elements; regex(""""reference":"([^"]+)"""").exists — validate and extract using regex; substring("Order confirmed").exists — simple substring check on the response body.
Interview tip: When asked "how do you know your performance test is actually testing the right thing?" the answer starts with checks: "Every HTTP request in my Gatling scenario includes at minimum a status code check and a response time check. For critical endpoints — login, checkout, payment — I add structural validation: JSON path checks confirming the response shape, field existence checks confirming required data is present, and value checks confirming business logic correctness. A load test without checks is indistinguishable from a DDoS attack — both generate traffic, but only one validates behaviour."
Assertions — Global Success Criteria
Assertions are evaluated at the end of the simulation across all users and all requests. They define the pass/fail criteria for the entire test run — if an assertion fails, Gatling exits with a non-zero status code, which is what CI/CD pipelines use to block deployments. Key assertion types: global.responseTime.percentile(95).lt(500) — 95th percentile response time must be under 500ms across all requests; global.responseTime.percentile(99).lt(1000) — 99th percentile under 1 second; global.successfulRequests.percent.gt(99) — more than 99% of requests must succeed; global.failedRequests.count.lt(10) — fewer than 10 total failures; details("Checkout").responseTime.max.lt(2000) — the Checkout endpoint specifically must have max response time under 2 seconds; global.requestsPerSec.gt(100) — the system sustained at least 100 requests per second of total throughput.
The assertion DSL is composable: You can scope assertions by request group (details("group")), by response time percentile or max, by success/failure count or percentage, and chain them with and(). Gatling's assertions are evaluated in order and the first failure is reported with the actual vs expected values — making CI pipeline failure messages immediately actionable. A strong interview answer: "I define assertions at three levels: global SLAs (p95 < 500ms, p99 < 1s, > 99% success), endpoint-specific thresholds (payment endpoint < 1s, search endpoint < 200ms), and throughput requirements (minimum requests per second to validate the load was actually generated). This gives me a layered pass/fail framework that catches both systemic degradation and endpoint-specific regressions."
// Layered assertion strategy in Gatling
setUp(scn.inject(rampUsers(1000).during(5.minutes)))
.protocols(httpProtocol)
.assertions(
// Layer 1: Global SLAs
global.responseTime.percentile(95).lt(500),
global.responseTime.percentile(99).lt(1000),
global.successfulRequests.percent.gt(99),
// Layer 2: Endpoint-specific thresholds
details("Checkout").responseTime.percentile(95).lt(1000),
details("Search").responseTime.percentile(95).lt(300),
details("Login").responseTime.percentile(95).lt(500),
// Layer 3: Throughput and failure caps
global.requestsPerSec.gt(50),
global.failedRequests.count.lt(5)
)
Gatling Reports and Metrics — What the HTML Report Tells You
"You've run a Gatling simulation. The HTML report is open. Walk me through what you look at first, and what each section tells you about system performance." This question tests whether you actually use Gatling reports to diagnose performance problems — or just run simulations and glance at the pass/fail icon.
The Gatling HTML Report Sections — And What Each One Reveals
1. Global Information: Start time, duration, total requests, total successes, total failures. Your first checkpoint: did the simulation run for the expected duration? Did the success rate meet the assertion threshold? 2. Response Time Distribution: A histogram showing the distribution of all response times across all requests. Look for: long tails (a small number of very slow requests pulling up the average), bimodal distributions (two peaks suggesting two different backend behaviours — cached vs uncached, for example), and the relationship between mean and percentiles (a mean of 200ms with a p99 of 5s tells you the system has catastrophic outliers). 3. Response Time Percentiles Over Time: A time-series graph showing how percentiles evolve during the test. Look for: degradation patterns (do response times increase linearly with load or jump at a specific threshold?), warm-up effects (do response times improve as caches populate?), and memory leaks (do response times degrade continuously throughout the test even with stable load?). 4. Active Users Over Time: Shows how many virtual users were active concurrently. For closed models, this should track your injection profile. A deviation means your injection profile and actual concurrency have diverged — which can happen when system slowdowns cause users to accumulate. 5. Requests Per Second Over Time: The actual throughput the system handled. Compare this against the injection rate — if the system can't sustain the injection rate, throughput will plateau below the target. The gap between target and actual throughput is your capacity deficit. 6. Response Time Distribution by Request: Per-endpoint breakdowns. Identify which specific endpoints are slow, and whether the bottleneck is isolated (one endpoint) or systemic (all endpoints degrade under load). 7. Details Table: Per-request statistics — count, min, max, mean, standard deviation, percentiles (50, 75, 95, 99). The standard deviation to mean ratio reveals response time consistency — high σ/μ means unpredictable performance.
Real-Time Metrics and External Dashboards
Gatling's HTML report is generated after the simulation completes — but for long-running tests (hours or days), you need real-time visibility. Gatling supports streaming metrics to: Graphite: The traditional Gatling metrics backend. Metrics are sent every N seconds via the Graphite protocol. Visualised in Grafana dashboards. Configuration: graphiteHost("graphite.internal").graphitePort(2003) in the Gatling configuration file. InfluxDB: Modern alternative to Graphite. Metrics are sent as InfluxDB data points. Also visualised in Grafana. Better suited for cloud-native infrastructure. Custom metrics: Gatling exposes a metrics API that you can tap into with custom code for proprietary monitoring systems.
The interview answer that demonstrates operational thinking: "For pipeline performance tests under 15 minutes, I use Gatling's built-in HTML report — it's self-contained and CI-friendly. For soak tests running hours or days, I stream metrics to InfluxDB and build a Grafana dashboard with: real-time response time percentiles, throughput trends, error rate alerts, and system-level metrics from the target service (CPU, memory, GC pauses, database connection pools) overlaid on the same time axis. The overlay is critical — it lets me correlate Gatling-level metrics (response time spike) with system-level metrics (CPU saturation, GC thrashing) to identify root causes during the test, not after it."
CI/CD Integration — Gatling with Maven, Gradle, Jenkins, and GitHub Actions
Performance tests that only run on a developer's laptop aren't performance testing — they're a curiosity. The real value comes when Gatling simulations run in CI/CD pipelines, blocking deployments that degrade performance. Interview panels test specifically for CI/CD integration knowledge because it's the difference between a performance testing enthusiast and a production-quality SDET.
Maven Integration — The Gatling Maven Plugin
The Gatling Maven Plugin is the most common integration path for JVM projects. Configuration: add the plugin to your pom.xml, specify the simulation class, and configure JVM arguments for the Gatling process (heap size, GC settings). The plugin wraps Gatling's lifecycle: compile simulations → run simulation → generate report. Key goals: mvn gatling:test runs the simulations (compile + execute + report). mvn gatling:recorder launches the Gatling Recorder GUI for recording browser sessions as simulations. Configuration options: <simulationClass> to run a specific simulation (without this, Gatling runs all simulations found on the classpath), <runMultipleSimulations> for running multiple simulation classes sequentially, <includes>/<excludes> for filtering by class name pattern, <jvmArgs> for passing JVM arguments (heap, GC, system properties), and <resultsFolder> for controlling report output location. The CI pipeline pattern: mvn gatling:test → check exit code (non-zero if assertions fail) → archive HTML report as a CI artifact → fail the build if assertions fail. For our comprehensive guide to CI/CD pipeline testing strategy covering Gatling, k6, and Selenium integration patterns, see our CI/CD Pipeline Testing Interview Questions guide.
Gradle Integration — The Gradle Gatling Plugin
For Gradle-based projects, the io.gatling.gradle plugin provides equivalent functionality. Apply the plugin in build.gradle, configure the Gatling extension block with simulation class and JVM args, and run ./gradlew gatlingRun. The Gradle plugin generates reports to build/reports/gatling/. Key advantages for Gradle users: incremental compilation of simulations (only recompile changed simulation files), integration with the Gradle build cache for CI speed, and native integration with Gradle's test task lifecycle. For multi-module Gradle projects, Gatling simulations typically live in a dedicated performance-tests or gatling-tests subproject — keeping the Gatling dependency isolated from the application code.
// GitHub Actions workflow — Gatling performance test gate
name: Performance Test Gate
on:
pull_request:
branches: [main]
paths:
- 'src/main/**'
- 'src/gatling/**'
jobs:
performance-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Start target service
run: |
./gradlew bootRun &
sleep 30 # Wait for service to be healthy
- name: Run Gatling simulations
run: ./gradlew gatlingRun # Non-zero exit if assertions fail
- name: Upload Gatling report
if: always()
uses: actions/upload-artifact@v4
with:
name: gatling-report
path: build/reports/gatling/
Pipeline design pattern — the answer that scores highest: "I design the performance testing pipeline in tiers. Tier 1 — Smoke: a 2-minute Gatling simulation with low load (10 concurrent users) that runs on every PR. Catches regressions before code review. Uses assertions with tight thresholds. Tier 2 — Baseline: a 10-minute simulation with production-representative load that runs on merge to main. Establishes the performance baseline that subsequent runs compare against. Uses historical-comparison assertions: p95 must not increase by more than 10% from the last 5 runs. Tier 3 — Soak: a multi-hour simulation that runs nightly. Catches memory leaks, connection pool exhaustion, and GC degradation that don't appear in short tests. Tier 4 — Spike: an on-demand simulation that tests failure recovery. Run before major releases or infrastructure changes. The tiered approach balances speed (fast feedback on PRs) with thoroughness (comprehensive testing before release)." This is the kind of architectural thinking that separates senior from mid-level candidates — and it's exactly the pipeline design methodology Mitchell's interview panels test for.
Feeders — Injecting Realistic Test Data for Production-Representative Load
A performance test with hardcoded data isn't realistic — it's a benchmark of a fictional system. Feeders are Gatling's mechanism for injecting dynamic, varied test data into simulations, and interviewers test whether you understand the difference between a simulation that stresses the database with repeated identical queries and one that exercises the full range of the data model.
Feeder Types and Strategies
CSV Feeder: The most common — reads rows from a CSV file, maps columns to session variables. Use when you have a static dataset: user credentials, product SKUs, search terms. Example: csv("users.csv").circular feeds user data from a CSV, looping when exhausted. JDBC Feeder: Queries a database and feeds each row as session variables. Use when your test data is generated by the application itself or lives in a shared test database. Example: jdbcFeeder("jdbc:postgresql://...", "user", "pass", "SELECT id FROM products LIMIT 10000"). JSON Feeder: Reads from JSON files or URLs — useful for API-driven test data sources. Example: jsonFile("products.json").circular. Custom Feeder: Implement the FeederBuilder trait for programmatic data generation — random strings, timestamps, UUIDs, or data computed from other session variables. Redis/S3 Feeder: For distributed Gatling setups where test data must be consistent across injector nodes. Feed from a shared Redis instance or S3 bucket.
Feeder strategies control consumption pattern: .queue — each virtual user takes the next record (default, sequential). .random — each user picks a random record (realistic for simulating diverse user populations). .shuffle — randomises the dataset once, then feeds sequentially (each record used exactly once). .circular — loops back to the beginning when exhausted (essential for tests longer than the dataset size). .eager vs .batch(n) — controls memory usage for large datasets.
Session Management — How Feeders Connect to the Scenario
Gatling maintains a Session for each virtual user — a mutable map of key-value pairs that flows through the scenario chain. Feeders populate session variables. Checks save extracted values back into the session. Subsequent requests reference session variables using Gatling's Expression Language: "$${username}" for string interpolation, "$${productId}" for dynamic request bodies. The session is the glue that makes feeders useful — it allows test data from a CSV to flow into HTTP request bodies, extracted response values to flow into subsequent requests, and dynamic values to flow through the entire scenario lifecycle.
Interview tip: When asked "how do you ensure your Gatling test represents real production traffic?" the answer centres on feeders: "I use CSV feeders populated from production access logs — sampling the actual distribution of URLs, HTTP methods, payload sizes, and user agents. For authenticated endpoints, I feed from a pool of test user credentials, each with different roles and permissions to exercise the authorisation layer. For search-heavy applications, I feed from a distribution of real search terms with realistic frequency weighting — the top 100 terms appear proportionally more often than the long tail. The goal is to exercise the actual access patterns of the system, not a uniform distribution that happens to be easy to generate. A simulated user clicking 'electronics' 100% of the time generates load that looks nothing like production — and finds performance problems that don't exist while missing the ones that do."
// Feeder example — CSV user data feeding into a login scenario
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class LoginSimulation extends Simulation {
// CSV feeder: username,password columns, circular strategy
val userFeeder = csv("users.csv").circular
val httpProtocol = http
.baseUrl("https://api.myapp.com")
.acceptHeader("application/json")
.contentTypeHeader("application/json")
val scn = scenario("Authenticated User Flow")
.feed(userFeeder) // Populate session with username and password
.exec(
http("Login")
.post("/auth/login")
.body(StringBody("""{"username":"$${username}","password":"$${password}"}"""))
.check(status.is(200))
.check(jsonPath("$.token").saveAs("authToken")) // Save token to session
)
.exec(
http("Get Orders")
.get("/api/orders")
.header("Authorization", "Bearer $${authToken}") // Use token from session
.check(status.is(200))
)
setUp(scn.inject(rampUsers(500).during(2.minutes)))
.protocols(httpProtocol)
}
Scala DSL vs Java DSL — Language Choice and Team Adoption
Gatling's native language is Scala, but it also offers a Java DSL. Interview panels at organisations adopting Gatling often ask about this choice — because the language decision affects hiring, maintainability, and how easily developers can contribute performance tests.
Scala DSL — The Native, Expressive Choice
The Scala DSL is Gatling's primary API and the one where the DSL's expressiveness shines. Benefits: concise — Scala's type inference, optional semicolons, and operator overloading produce simulations that are roughly 30-40% shorter than equivalent Java DSL code; feature-complete — Gatling's documentation and examples are Scala-first, and new features arrive in Scala DSL before Java DSL; compile-time safety — the Scala compiler catches type errors in checks, assertions, and body transformations at build time, not runtime; powerful abstractions — Scala's for-comprehensions, pattern matching, and implicit conversions enable elegant refactoring of simulation logic. The downside: Scala expertise is rarer than Java expertise, which creates a hiring and onboarding challenge for organisations without existing Scala capability. However, Gatling's Scala DSL uses a restricted subset of Scala — you can write effective Gatling simulations knowing only the DSL patterns without deep Scala language expertise.
Java DSL — The Accessible, Verbose Alternative
The Java DSL was introduced in Gatling 3.7 (2021) and has matured significantly. Benefits: accessible to any Java developer — which represents the largest pool of engineers in enterprise environments; integrates with existing Java build tooling (Maven, Gradle) without requiring the Scala compiler plugin; and enables performance tests to live in the same repository as the Java application code with the same language toolchain. The trade-off: verbosity — Java's lack of operator overloading means the DSL is significantly more verbose than the Scala equivalent (each request builder requires explicit method chaining rather than the Scala DSL's operator-based syntax); feature lag — the Java DSL lags behind the Scala DSL by several months for new Gatling features; and less idiomatic patterns — Java's static type system and absence of implicits make some Gatling patterns (like session manipulation) more cumbersome.
The interview answer: "I recommend the Scala DSL when the team already has Scala expertise or is willing to invest a small amount of time learning Gatling's Scala subset — the productivity gain from the more expressive DSL justifies the learning investment for teams that will write and maintain performance tests long-term. I recommend the Java DSL when the organisation is Java-only, the performance tests will be written by backend developers who don't have Scala exposure, and the onboarding benefit of using a familiar language outweighs the DSL's verbosity. The right choice depends on the team, not the tool — a Java DSL simulation that gets written and maintained is infinitely more valuable than a Scala DSL simulation that nobody on the team feels confident modifying."
// Same scenario — Scala DSL vs Java DSL side by side
// === Scala DSL (concise, using operators) ===
val scn = scenario("Checkout")
.exec(http("Search").get("/api/search?q=$${term}").check(status.is(200)))
.exec(http("Checkout").post("/api/checkout").body(StringBody("""{"cart":"$${cartId}"}""")).check(status.is(201)))
// === Java DSL (verbose, using method chaining) ===
ScenarioBuilder scn = scenario("Checkout")
.exec(http("Search").get("/api/search?q=#{term}").check(status().is(200)))
.exec(http("Checkout").post("/api/checkout").body(StringBody("{"cart":"#{cartId}"}")).check(status().is(201)));
What Interviewers Ask About Gatling — The Question Bank
After 20 years of SDET interview panels, Mitchell has catalogued the Gatling-specific questions that appear most frequently in senior and lead-level performance testing rounds. Here's the question bank with the answer patterns that score highest:
Question 1: "Explain Gatling's architecture — why doesn't it use threads like JMeter?"
What they're testing: Whether you understand the fundamental architectural decision that makes Gatling different — async non-blocking actors vs thread-per-user model. This is the gateway question; candidates who can't answer it signal that they've only used the DSL without understanding the engine.
High-scoring answer: "Gatling uses the Akka actor model instead of threads. Each virtual user is a lightweight actor — about 300 bytes of memory — scheduled on a small thread pool by the Akka dispatcher. HTTP requests are non-blocking: when an actor makes a request, it registers a callback and releases its thread, allowing the same thread pool to serve thousands of concurrent actors. JMeter creates a dedicated thread per virtual user — 10,000 users need 10,000 threads, consuming gigabytes of memory from thread stacks and suffering context-switching overhead. Gatling can simulate tens of thousands of concurrent users on a single machine because actors don't map 1:1 to threads. This architecture also mirrors how reactive JVM applications (Akka HTTP, Spring WebFlux) work — so Gatling generates architecturally realistic load."
Question 2: "When would you use Gatling instead of k6 or JMeter?"
What they're testing: Contextual decision-making — the ability to match tools to team and project requirements. Tool evangelism scores lower than contextual reasoning.
High-scoring answer: "I choose Gatling when: the organisation is a JVM shop with Scala or Java expertise; we need maximum per-machine throughput for high-concurrency testing; we value compile-time safety in performance tests — catching type errors at build time rather than runtime; the backend team who owns the service will also own the performance tests, and they work in Scala or Java; we're testing reactive, non-blocking JVM services where Gatling's actor model mirrors the production architecture. I choose k6 when the team is JavaScript/TypeScript-based and values low adoption barrier over maximum per-machine throughput. I choose JMeter when I need protocol support beyond HTTP — JDBC, JMS, FTP — or when a non-developer QA team needs a GUI test builder. The tool follows the team, not the other way around."
Question 3: "What's the difference between open and closed workload models in Gatling?"
What they're testing: Load modelling competence — the conceptual understanding that separates performance engineers from script writers.
High-scoring answer: "In a closed model, a fixed pool of users repeatedly executes a scenario. The arrival rate depends on system response time — if the system slows down, users take longer per iteration and the request rate drops naturally. This models user-facing web applications where each user navigates through a flow. Gatling's closed injectors include rampUsers and constantConcurrentUsers. In an open model, users are injected at a fixed rate per second regardless of response times. If the system slows down, concurrent users accumulate unboundedly. This models API services and messaging systems where requests arrive at a fixed rate from upstream services. Gatling's open injectors include constantUsersPerSec and rampUsersPerSec. I use closed models for user-facing flows with think times, open models for API endpoints with fixed arrival rates, and hybrid models for systems that serve both."
Question 4: "How do you integrate Gatling into a CI/CD pipeline?"
What they're testing: Production readiness — whether you've moved beyond running simulations locally.
High-scoring answer: "I use a tiered performance testing pipeline. Tier 1 — Smoke: a 2-minute Gatling simulation with low load runs on every PR via a Maven or Gradle task. It uses tight assertions and fails the build if they're violated — catching performance regressions before code review. Tier 2 — Baseline: a 10-minute simulation with production-representative load runs on merge to main. I use historical-comparison assertions — p95 response time must not increase by more than 10% from the rolling average of the last 5 runs. Tier 3 — Soak: multi-hour simulations run nightly to catch memory leaks, connection pool exhaustion, and GC degradation. Tier 4 — Spike: on-demand simulations for failure recovery testing before major releases. Gatling's non-zero exit code on assertion failure makes CI integration straightforward — the build step simply checks the exit code. The HTML report is archived as a CI artifact for debugging."
The meta-pattern that scores highest: interviewers are screening for candidates who can engineer performance tests, not just write them. The strongest answers demonstrate architectural understanding (actor model, non-blocking I/O, injection profiles), comparative reasoning (Gatling vs k6 vs JMeter — not advocacy, analysis), production-grade pipeline thinking (tiered testing, CI integration, historical baselines), and the ability to discuss Gatling in the context of the broader SDET skillset — including the testing methodology and bottleneck analysis that are framework-agnostic. This is exactly what the SDET Interview Coach iOS app trains you to do — the Performance Testing topic covers Gatling, k6, and JMeter with mock interviews scored across technical accuracy, completeness, and communication. Download it and practise the exact performance testing questions panels ask.
Further Reading and Interview Preparation
This guide covers Gatling-specific interview questions. To complete your performance testing interview preparation across the full tool landscape:
- k6 Performance Testing Interview Questions — Complete coverage of k6, the JavaScript/Go-based load testing tool that dominates developer-centric performance engineering. Covers k6 architecture, executor types, thresholds, checks, Grafana Cloud integration, and the k6 vs Gatling vs JMeter comparison from the k6 perspective.
- CI/CD Pipeline Testing Interview Questions — How to integrate performance testing — including Gatling — into CI/CD pipelines. Covers tiered testing strategies, performance regression detection, pipeline gate design, historical baseline comparison, and the build-vs-buy decision for performance testing infrastructure.
- Test Automation Framework Design Interview Guide — The framework design methodology that applies to performance testing frameworks as much as functional testing. Covers layered architecture, test data strategy, parallel execution patterns, and the organisational design patterns that make frameworks maintainable at scale.
The SDET Interview Coach iOS app brings all of this together — 800+ questions across 32 topics, including a dedicated Performance Testing module covering Gatling, k6, and JMeter with AI-graded mock interviews. The app's Job Match feature analyses any SDET job description and generates 50 bespoke questions targeting the specific tools and technologies mentioned — including Gatling. Download it on the App Store and walk into your interview with the confidence that comes from having practised the exact questions panels ask.
Ready to Transform Your Testing?
The AI Test Automation Playbook gives you everything you need: Playwright setup, Claude AI integration, MCP deep dive, 10+ ready-to-use prompts, CI/CD pipeline setup, and a 30-day implementation roadmap.
By Mitchell Agoma, Senior SDET & AI Testing Specialist with 8+ years of experience