Using Gatling Expression Language to Extract and Reuse Dynamic Values in Load Tests
Learn how Gatling’s Expression Language lets you pull tokens, IDs, or other dynamic data from HTTP responses and reuse them in later requests—making your load tests realistic and maintainable.
27 Jul 2026, 08:08 UTC

Problem: Hard‑coded values break realistic scenarios
When you record a user journey, many values such as authentication tokens, session IDs, or product identifiers are generated by the server and differ for each virtual user. If you keep those values hard‑coded in your Gatling script, the simulated traffic will either fail (e.g., 401 Unauthorized) or produce unrealistic load because every virtual user repeats the exact same data.
Thesis: Gatling’s Expression Language (EL) lets you pull values from previous responses, store them in the session, and reuse them later—without writing custom Scala code.
How EL works in Gatling
EL uses the ${…} syntax to reference session variables at the moment a request is built. The variable is resolved just before the request is sent, so any value you stored earlier (via a feeder, a check, or session.set) can be interpolated into URLs, headers, bodies, or checks.
Typical flow:
- Capture a value from a response with a check (
regex,jsonPath,css, etc.) and store it under a name. - Reference that name later with
${name}wherever you need it. - If the value is missing or malformed, the check fails and the error appears in the detailed Gatling report.
Worked example: extracting a JWT and sending it in the next request
Assume a login endpoint returns a JSON body { "token": "eyJ..." }. The following Scala snippet shows how to save the token and reuse it in a subsequent API call.
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class TokenFlow extends Simulation {
val httpProtocol = http
.baseUrl("https://api.example.com")
.acceptHeader("application/json")
val scn = scenario("Login then fetch profile")
.exec(
http("Login")
.post("/auth/login")
.body(StringBody("""{ "username": "gatling_user", "password": "secret" }"""))
.asJson
.check(status.is(200))
.check(jsonPath("$.token").saveAs("authToken")) // <‑‑ store token
)
.exec(
http("Get Profile")
.get("/profile")
.header("Authorization", "Bearer ${authToken}") // <‑‑ EL interpolation
.check(status.is(200))
)
setUp(scn.inject(constantUsersPerSec(10) during (30.seconds)))
.protocols(httpProtocol)
}
Explanation:
- The
jsonPathcheck extracts thetokenfield and saves it to the session under the keyauthToken. - In the second request,
${authToken}is replaced by the actual token value just before the request is sent. - If the login fails or the token is absent, the check fails and the user is marked as failed; the simulation continues with other users.
Trade‑off: EL overhead at very high scale
EL resolution is cheap for simple variable look‑ups, but complex expressions (e.g., nested if, custom methods, or heavy regex) are evaluated for every request. When you run tens of thousands of virtual users, this can add measurable CPU usage. To keep the impact low:
- Prefer plain variable references (
${var}) over inline logic. - If you need complex calculations, compute them once in a feeder or a
session.setstep and reuse the result. - Run a short baseline test with a modest user count, enable JVM profiling (e.g.,
-XX:+PrintCompilation), and compare CPU usage with and without the complex EL.
Verification steps before you run a full test
- Compile‑time EL check: Run
gatling:test(orsbt gatling:test) and look at the console output. Any unresolved${…}references will appear as compilation errors. - Dry‑run with a single user: Execute the simulation with
constantUsersPerSec(1) during (5.seconds). Open the generated report and verify that theauthTokenvalue appears in the request headers of the second call. - Session inspection (optional): If you use an IDE, place a breakpoint on
session.set("authToken", …)or add aexec(session => { println(session); session })step to see the session content.
These steps give you confidence that the EL expressions are syntactically correct and that the values are being stored and substituted as expected.
Closing: Make your load tests data‑driven with EL
By extracting dynamic values from responses and re‑using them via Gatling’s Expression Language, you avoid hard‑coded data, improve realism, and keep your scripts maintainable. Start with simple ${var} references, profile if you add complex logic, and always verify with a small‑scale run before scaling up. This approach works the same in Gatling 2.3+ and the current 3.x line, so you can adopt it without worrying about version‑specific quirks.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.