Back to guides

GUIDE / performance

Gatling Tutorial: Build Your First Load Test

Follow this Gatling tutorial to create a load test, model users, add checks, use feeders, set thresholds, read reports, and avoid common mistakes.

By The Testing AcademyPublished July 10, 2026Updated July 10, 202614 min read

This Gatling tutorial shows how to build a practical load test from the ground up. Gatling is a code based performance testing tool that helps you model user behavior, send HTTP requests, add checks, feed dynamic data, shape load, and read detailed reports. It is especially useful when performance tests need to live in source control and run in CI.

You will learn the core Gatling workflow, how a simulation is structured, how to write a first scenario, how to add assertions, how to use test data, and how to avoid beginner mistakes that make performance results misleading.

Gatling Tutorial: The Core Workflow

Every Gatling test follows the same basic flow:

  1. Define the HTTP protocol configuration.
  2. Define a scenario, which is the user journey.
  3. Add requests and checks inside the scenario.
  4. Define how virtual users are injected.
  5. Run the simulation.
  6. Review the report.
  7. Compare results against a performance target.

This structure is one reason Gatling is popular with engineering teams. A simulation reads like a performance model: what system, what users, what actions, what load, what result.

Gatling is not a replacement for performance thinking. You still need realistic scenarios, stable environments, clean test data, monitoring, and clear goals. A beautiful script with unrealistic traffic produces weak evidence.

When to Use Gatling

Gatling is a strong choice when:

  • You test HTTP APIs or web application backend flows.
  • Your team is comfortable with code review.
  • You want detailed reports.
  • You need scenario based load modeling.
  • You want tests to run from CI/CD.
  • You need dynamic data with feeders.
  • You care about percentiles and error rates, not only averages.

Gatling may not be the best first choice if the team strongly prefers GUI based scripting or needs many legacy protocols. In that case, compare options in JMeter vs k6 vs Gatling.

Key Gatling Concepts

Before writing a script, understand the vocabulary.

ConceptMeaningExample
SimulationThe complete performance test class or fileCheckoutSimulation
ProtocolBase URL, headers, connection settingsHTTP base URL and accept header
ScenarioUser behavior modelSearch product, add to cart, checkout
RequestOne HTTP callGET /products
CheckValidation on a responseStatus is 200, JSON field exists
FeederDynamic test data sourceCSV of users or product IDs
Injection profileHow users arriveRamp 100 users over 10 minutes
AssertionPass or fail rule for the runp95 response time under 500 ms

If you understand those concepts, syntax becomes easier.

A Simple Gatling Simulation

The exact syntax depends on your Gatling project language, but the structure below shows the important parts. It uses a Java style example because many QA teams are familiar with Java based automation.

import static io.gatling.javaapi.core.CoreDsl.*;
import static io.gatling.javaapi.http.HttpDsl.*;

import io.gatling.javaapi.core.*;
import io.gatling.javaapi.http.*;

public class ProductApiSimulation extends Simulation {

  HttpProtocolBuilder httpProtocol = http
    .baseUrl("https://api.example.com")
    .acceptHeader("application/json")
    .userAgentHeader("QABattle-Gatling-Tutorial");

  ScenarioBuilder browseProducts = scenario("Browse products")
    .exec(
      http("List products")
        .get("/products")
        .check(status().is(200))
    )
    .pause(1)
    .exec(
      http("Open product details")
        .get("/products/1001")
        .check(status().is(200))
        .check(jsonPath("$.id").is("1001"))
    );

  {
    setUp(
      browseProducts.injectOpen(
        rampUsers(50).during(300)
      )
    )
    .protocols(httpProtocol)
    .assertions(
      global().failedRequests().percent().lt(1.0),
      global().responseTime().percentile3().lt(500)
    );
  }
}

Read it from top to bottom. The protocol defines where requests go. The scenario defines what a user does. The injection profile defines how many users arrive and over what time. Assertions define whether the run is acceptable.

Choosing a First Scenario

Beginners often choose a scenario that is too large. Do not start with a complete purchase journey involving login, search, cart, coupon, payment, email, invoice, and reporting. Start with one meaningful flow.

Good first scenarios:

  • Search products and open a detail page.
  • Login and fetch the current profile.
  • Create a draft record through an API.
  • Retrieve an order summary.
  • Submit a small form with controlled data.

Weak first scenarios:

  • Full end to end checkout with real payment dependency.
  • A flow that requires manual captcha.
  • A journey that depends on unstable third party services.
  • A scenario with no clear response time goal.
  • A script copied from production traffic without understanding it.

The first test should teach the team how Gatling behaves and how the system responds under light load. After that, expand.

Project Structure for Maintainable Simulations

A Gatling project can become messy if every simulation copies URLs, headers, test data, and helper logic. Keep structure simple from the beginning.

A practical layout:

src/test/java
  simulations/
    ProductBrowseSimulation.java
    CheckoutSimulation.java
  support/
    Headers.java
    Environment.java
    TestData.java
src/test/resources
  data/
    users.csv
    products.csv

The exact folders depend on your build tool, but the principle is universal. Simulations should describe behavior. Support classes should handle reusable configuration. Data files should be easy to inspect and replace per environment.

Avoid hardcoding base URLs, credentials, and secrets in simulations. Read them from environment variables, system properties, or CI configuration. This keeps the same simulation usable locally, in staging, and in a release pipeline.

Good naming also matters. LoadTest1 tells reviewers nothing. CheckoutGuestUserSimulation is clearer. Request names should describe business actions, such as Search products, Add item to cart, and Submit order, not just GET 1 or POST 2.

Adding Checks

Checks make a performance test honest. Without checks, a server can return error pages quickly and the report may look fast. Always validate that the response is correct enough for the scenario.

Common checks:

  • HTTP status is expected.
  • JSON field exists.
  • Response body contains an expected value.
  • Header is present.
  • Redirect target is correct.
  • Response time threshold is met through assertions.

Example:

http("Get user profile")
  .get("/me")
  .check(status().is(200))
  .check(jsonPath("$.email").exists())
  .check(jsonPath("$.role").is("buyer"));

Do not overdo body checks in every request. Validate what matters. Heavy checks can add client side overhead. The goal is to ensure the scenario is doing real work and not silently failing.

Using Feeders for Dynamic Data

Realistic performance tests need data variation. If every virtual user searches for the same product or logs in as the same account, the system may cache behavior unrealistically or create data conflicts.

A feeder supplies data to virtual users. A CSV might look like this:

email,password,productId
buyer1@example.com,Password#2026,1001
buyer2@example.com,Password#2026,1002
buyer3@example.com,Password#2026,1003

A scenario can read values from the feeder:

FeederBuilder.FileBased<Object> users = csv("users.csv").circular();

ScenarioBuilder profileScenario = scenario("Profile lookup")
  .feed(users)
  .exec(
    http("Login")
      .post("/login")
      .body(StringBody("{\"email\":\"#{email}\",\"password\":\"#{password}\"}"))
      .asJson()
      .check(status().is(200))
  )
  .exec(
    http("Open product")
      .get("/products/#{productId}")
      .check(status().is(200))
  );

Use feeders carefully. If a scenario changes account state, circular reuse may create conflicts under high load. For destructive tests, use enough unique rows or create data dynamically.

Correlation and Session Data

Many real applications require values from one response to be sent in the next request. Examples include authentication tokens, CSRF tokens, cart IDs, order IDs, and pagination cursors. This is called correlation. Without it, a script may work once with hardcoded values and fail as soon as virtual users increase.

Example flow:

1. Login.
2. Extract access token from response.
3. Use token in Authorization header.
4. Create cart.
5. Extract cart ID.
6. Add product to that cart.

In Gatling, you usually save extracted values into the session and reuse them later. The concept is more important than the exact syntax. Every virtual user has session state. Values saved for one virtual user should not leak into another virtual user's journey.

Correlation review checklist:

  • Are tokens extracted dynamically?
  • Are IDs created by setup calls reused correctly?
  • Does each virtual user have its own session data?
  • Are hardcoded values limited to safe static configuration?
  • Does the script fail clearly when extraction fails?

If a Gatling scenario returns many 401, 403, 404, or validation errors under load, inspect correlation before blaming the application.

Modeling Load

Load shape matters. A system that survives 100 users gradually ramping over 20 minutes may fail when 100 users arrive in 10 seconds. Choose a profile that matches the question.

Common load models:

ModelPurposeExample
Smoke loadVerify script and environment5 users for 2 minutes
Load testExpected production traffic200 users over 30 minutes
Stress testFind breaking pointIncrease until error rate rises
Spike testSudden traffic burst500 users in 30 seconds
Soak testLong term stability100 users for 6 hours

For terminology and planning, see load vs stress vs soak vs spike testing.

Start with a smoke load. If the script fails with five users, it is not ready for 500. Once the script and environment are stable, increase load gradually.

Connecting Gatling Results to Server Metrics

Gatling reports show client side experience. They tell you how long requests took, how many failed, and how performance changed during the test. They do not automatically tell you the root cause. Pair every serious run with server monitoring.

Watch these signals during the run:

  • Application CPU and memory.
  • Database CPU, locks, slow queries, and connection pool usage.
  • Cache hit rate.
  • Queue depth and processing delay.
  • External dependency latency.
  • Error logs.
  • Garbage collection behavior for JVM services.
  • Container restarts or throttling.

Then connect symptoms to causes. If p95 response time rises while database CPU is saturated, investigate queries and indexes. If failed requests increase while the app logs connection pool timeouts, inspect pool sizing and slow downstream calls. If Gatling is CPU saturated, the load generator may be the bottleneck.

Performance testing becomes much more useful when QA, developers, SRE, and database owners review the same timeline together.

Assertions and Thresholds

Assertions define pass or fail criteria for the run. Without assertions, a Gatling report may be interesting but not decisive.

Useful assertions:

  • Failed requests below 1 percent.
  • p95 response time below the target.
  • Specific request p95 below a target.
  • Maximum response time below a tolerance.
  • Requests per second above expected throughput.

Example:

.assertions(
  global().failedRequests().percent().lt(1.0),
  details("List products").responseTime().percentile3().lt(400),
  details("Open product details").responseTime().percentile3().lt(600)
)

Do not set thresholds randomly. Base them on product expectations, service level objectives, historical baselines, or user experience needs. For API timing context, read what is a good API response time.

Reading the Gatling Report

After a run, Gatling generates a report that helps you analyze performance. Start with the high level summary:

  • Did any requests fail?
  • What was the overall response time distribution?
  • What were p95 and p99?
  • Did response times worsen as users increased?
  • Which request was slowest?
  • Did throughput match the load model?

Then inspect request details. A single slow endpoint can hide behind a decent global average. Percentiles are more useful than averages because users experience the tail. If p95 is 900 ms, then 5 percent of requests were slower than that.

Also compare report timing with server monitoring. Gatling tells you what the client experienced. Server metrics tell you why: CPU, memory, database, cache, queue, garbage collection, external dependency, or lock contention.

For deeper report habits, see how to read a performance test report.

Running Gatling in CI

Gatling can run in CI like other test tools. The important parts are configuration and artifacts.

CI checklist:

  • Use environment variables for base URLs and credentials.
  • Run a small performance smoke test on merge.
  • Run heavier tests nightly or before release.
  • Publish Gatling reports as artifacts.
  • Fail builds only on meaningful thresholds.
  • Keep test data stable.
  • Ensure the target environment is dedicated or controlled.

Do not run a heavy load test against a shared staging environment without warning. Performance tests can disturb other teams, trigger rate limits, fill logs, or consume database capacity.

Expanding From API to User Journeys

After your first API simulation works, expand toward realistic user journeys. A journey does not need to click through a browser. It should model the network behavior behind a real user action.

Example checkout journey:

1. Open product list.
2. Open product details.
3. Create cart.
4. Add product.
5. Apply coupon.
6. Estimate shipping.
7. Submit order using a test payment method.
8. Fetch order confirmation.

Add pauses between actions to represent human think time. Use feeders for users, products, coupons, and addresses. Add checks after each important step. Keep payment and email dependencies controlled with sandbox systems or mocks where appropriate.

Do not include every background request from a recorded browser session. Fonts, analytics, tracking pixels, and static assets may not belong in an API level Gatling simulation unless they are part of the performance question. Focus on the backend behavior you need to measure.

Common Mistakes in a Gatling Tutorial Project

Mistake 1: Starting With Too Much Load

Run a smoke load first. If the script, data, or environment is wrong, high load only creates noisy failures.

Mistake 2: Forgetting Checks

A fast 500 error is still a failed request. Validate status and important response fields.

Mistake 3: Using One Account for Every User

Shared accounts distort results and create collisions. Use feeders, account pools, or dynamic setup.

Mistake 4: Ignoring Think Time

Real users pause between actions. Without pauses, your script may generate unrealistic request bursts.

Mistake 5: Testing in an Unmonitored Environment

Gatling reports tell you symptoms. Server monitoring tells you causes. Use both.

Mistake 6: Treating Average Response Time as Enough

Averages hide tail latency. Look at percentiles, especially p95 and p99.

Mistake 7: Setting Random Assertions

Thresholds should come from business needs, baselines, or service objectives. Arbitrary thresholds create false confidence or false alarms.

A Practical Learning Path

Use this path to learn Gatling without getting lost:

  1. Run a sample simulation locally.
  2. Replace the base URL with a test API.
  3. Add one GET request with a status check.
  4. Add a second request and a pause.
  5. Add a feeder with dynamic data.
  6. Add a p95 response time assertion.
  7. Run a smoke load.
  8. Increase users gradually.
  9. Publish the report in CI.
  10. Compare results with server metrics.

This path teaches the whole workflow without hiding behind a giant demo.

Team Review Checklist

Before a Gatling simulation becomes a release gate, ask the team to review it.

Review AreaQuestion
Scenario valueDoes this represent a real user or system risk?
DataIs data unique, realistic, and safe to reuse?
ChecksWill the test detect bad responses, not just fast responses?
Load modelDoes the user injection profile match the objective?
ThresholdsAre assertions tied to a performance target?
EnvironmentIs the target environment controlled and monitored?
ArtifactsAre reports saved where the team can inspect them?
MaintenanceCan another engineer update this simulation confidently?

This review prevents a common failure: a performance script exists, but nobody trusts it enough to act on it. A reviewed simulation becomes part of the delivery system.

You can also practice scenario design in QABattle. Pick a performance challenge, define what a virtual user does, then write the load profile and pass criteria before touching the tool. That planning step is what separates a real performance test from a script that only sends traffic.

Final Checklist

Before you trust a Gatling result, confirm:

  • The scenario reflects a real user or system behavior.
  • The base URL points to the intended environment.
  • Requests include realistic headers and authentication.
  • Checks validate correct responses.
  • Test data is varied and safe.
  • Load profile matches the question being asked.
  • Assertions express release criteria.
  • Server monitoring ran during the test.
  • Reports are saved and compared to baselines.
  • The load generator was not the bottleneck.

This Gatling tutorial gives you the first complete loop: scenario, data, load, checks, assertions, report, and decision. Once that loop is stable, the tool becomes much more than a traffic generator. It becomes a repeatable way to discuss performance risk with evidence.

FAQ

Questions testers ask

Is Gatling good for beginners?

Gatling is good for beginners who are comfortable reading code and want to learn performance testing with structured simulations. It has a learning curve, but the core ideas are clear: define a protocol, write a scenario, inject users, run the simulation, and inspect the report.

What language does Gatling use?

Gatling simulations are written with a code based DSL. Depending on the Gatling version and project setup, teams commonly use Java, Scala, or Kotlin style APIs. The important skill is understanding scenarios, checks, feeders, and load profiles, not memorizing syntax alone.

Can Gatling test APIs?

Yes. Gatling is very strong for HTTP API performance testing. It can send requests, add headers and authentication, validate status codes and response bodies, use dynamic data, model user journeys, and generate detailed performance reports.

How is Gatling different from JMeter?

Gatling is code first and focuses on simulations and efficient HTTP load generation. JMeter is GUI first with broad protocol support and a large plugin ecosystem. Gatling often fits engineering teams that want performance tests reviewed and maintained like code.

What should I check in a Gatling report?

Start with failed requests, error rate, p95 and p99 response times, throughput, active users, and response time trends over the run. Compare results to a target, such as p95 under 500 ms and error rate below 1 percent.