skip to content

File Backed Records

Reading virtual-user data out of a delimited file, a JSON document, a sitemap, a SQL query or Redis, and where those files must live. A filesystem path where a classpath path belongs fails first.

on this pageshow

explore

questions

6

In a Gatling simulation, which built-in feeders read a character-separated file, and where must the file sit for csv("credentials.csv") to resolve?

level: juniorimportance: must knowfreq 70%

answer

  1. data comes from outside the simulation
  2. four delimited builders, plus JSON and sitemap
  3. classpath root, not a project path
  4. csv, ssv, tsv, separatedValues(path, separator)
  5. optional argument is quoteChar, default double quote

basics

~10 s

Gatling ships csv, tsv, ssv and separatedValues for delimited files, plus jsonFile, jsonUrl and sitemap. The path is resolved from your classpath root: src/main/resources or src/test/resources on the JVM, resources in the JavaScript SDK.

solid answer

~40 s

Four built-ins read character-separated files: `csv` (comma), `ssv` (semicolon), `tsv` (tab) and `separatedValues(path, separator)` for anything else. Each takes an optional `quoteChar` argument, defaulting to a double quote — second for `csv`, `ssv` and `tsv`, third for `separatedValues`, whose second argument is the separator itself; there is no `quotes` method. `jsonFile` reads a JSON array of objects, `jsonUrl` fetches one over HTTP, and `sitemap` reads a sitemap XML file but lives in the HTTP DSL rather than core. The argument is a **classpath** path, not a filesystem path: put the file under `src/main/resources`, `src/test/resources`, or `src/gatling/resources` under Gradle, and pass the path relative to that root, so `csv("data/credentials.csv")`. The JavaScript and TypeScript SDK uses a `resources` folder instead. An absolute filesystem path also works when data files ship separately from the simulation.

code

java · 10 lines
java
import io.gatling.javaapi.core.*;

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

public class CredentialFeeders {
  FeederBuilder.FileBased<String> commas = csv("data/credentials.csv");
  FeederBuilder.FileBased<String> pipes = separatedValues("data/credentials.txt", '|');
  FeederBuilder.FileBased<String> singleQuoted = csv("data/credentials.csv", '\'');
  FeederBuilder.FileBased<String> compressed = csv("data/credentials.csv.gz").unzip();
}

go deeper

for a junior

Be ready to name the four delimited-file builders and say where the file goes. Reciting csv, ssv, tsv and separatedValues plus the classpath root covers most of what is asked at this level.

for a middle

Explain that the argument is a classpath path resolved when the builder is created, that the optional extra argument is quoteChar rather than the separator, and that sitemap comes from the HTTP DSL.

for a senior

Be able to justify a builder choice for a supplied data file, including when unzip and transform earn their place and what an absolute path buys you when the data ships separately from the artifact.

for a principal

Own the convention across the suite: whether feeder data lives inside the built artifact or beside the load generator, and what that settles about reproducibility, artifact size and how the file reaches every generator.

## What a feeder actually is A **feeder** is a stock of records that virtual users draw on, so that a thousand simulated logins do not all send the same username. The SDK exposes a `feed` method that can be placed wherever `exec` is placed. Every time a virtual user reaches that step it collects one record, and Gatling merges that record's keys into the user's Session as attributes, ready for `#{username}` style interpolation. A record is just a map of names to values; the names come from the source itself — a CSV header line, a JSON object's keys, a sitemap element's tags. ## The character-separated family Four builders read delimited files. They are the same RFC 4180 parser with a different separator baked in: | builder | separator | optional quote-char argument | |---|---|---| | `csv(path)` | comma | `quoteChar`, default `"` | | `ssv(path)` | semicolon | `quoteChar`, default `"` | | `tsv(path)` | tab | `quoteChar`, default `"` | | `separatedValues(path, separator)` | whatever you pass | `quoteChar`, default `"` (third argument, after the separator) | Two things trip people up. `ssv` is **semicolon**-separated, not space-separated. And that optional extra parameter is the **quote character**, not the separator — there is no `quotes` method, so `csv("x.csv", ';')` makes `;` the quote character and leaves the separator a comma. Only `separatedValues` takes a separator argument at all, because it has none baked in: there the separator is the mandatory second argument and `quoteChar` moves to third. The one documented deviation from RFC 4180 is that header fields are trimmed of wrapping whitespace. ## The other file-backed sources * `jsonFile(path)` reads a JSON document whose **root node must be an array**. Each object in that array becomes one record, and its keys become the attribute names. * `jsonUrl(url)` reads the same shape over HTTP instead of off the classpath. * `sitemap(path)` reads a sitemap XML file, turning each `<url>` element into a record carrying `loc`, and `lastmod`, `changefreq` and `priority` where the element has them. It lives in the **HTTP** DSL, not core — `io.gatling.javaapi.http.HttpDsl` for Java and Kotlin, `io.gatling.http.Predef._` for Scala, `@gatling.io/http` for JavaScript and TypeScript — so a simulation that imports only the core DSL will not see it. ## Where the file has to sit The string you pass is a **classpath** path, not a filesystem path. 1. On the JVM SDKs, put the file under `src/main/resources` or `src/test/resources`, or under `src/gatling/resources` when you build with Gradle. 2. In the JavaScript and TypeScript SDK, put it under `resources`. 3. Pass the path **relative to that root**. A file at `src/test/resources/data/credentials.csv` is declared as `csv("data/credentials.csv")`. The documented alternative is an **absolute** filesystem path, which is how you deploy data files separately from the packaged simulation and let them sit on the load generator's own disk. What is not accepted is a path that names your source tree, such as `src/main/resources/data/credentials.csv`: Gatling recognises that prefix and refuses it with a message telling you to drop it. ## What you can chain onto the builder The builder is immutable — every call returns a new one, so keep the value: * `unzip()` for a gzip or zip source, decompressed on the fly. * `transform(...)` to convert a value before the user sees it, because a delimited file yields only `String`s. Java and Kotlin take a `BiFunction<String, T, Object>` over key and value; Scala takes a `PartialFunction[(String, T), Any]` defined only for the keys you want changed. * `recordsCount()` for the number of records, and `readRecords()` for the records themselves. * `shard()`, which slices the data across load generators on Gatling Enterprise and is a no-op anywhere else. In Scala these parameterless calls are written without parentheses — `csv("x.csv").unzip`, not `unzip()` — which is the usual cross-SDK spelling difference rather than a different feature. ## What the record turns into Whatever the source, a record is a map and its keys become Session attributes for that one virtual user. That has two consequences worth stating out loud: * The attribute names are decided by the **data**, not by the simulation. Rename a CSV column and every `#{...}` placeholder that referred to it silently stops resolving. * Values from a delimited file are always `String`. A JSON feeder preserves the document's own types, so a numeric field arrives as a number without any `transform` at all. ## The worked example A login scenario backed by a 200,000-row credentials file is the ordinary case. The file goes to `src/test/resources/data/credentials.csv` with a header line reading `username,password`, the simulation declares `csv("data/credentials.csv")`, and the scenario interpolates `#{username}` and `#{password}` into the login request. Nothing about the row count changes the declaration: size only affects how Gatling loads the file at run start, not how you name it.

  • In Gatling, how do you read a file whose columns are separated by a pipe character?
    Use `separatedValues("data/credentials.txt", '|')`. `csv`, `ssv` and `tsv` are fixed-separator shorthands over exactly the same parser — comma, semicolon and tab. All four accept a further optional argument, `quoteChar`, when the file quotes fields with something other than a double quote.
  • A Gatling CSV feeder hands every column over as a String. How do you turn one column into an Int?
    Chain `transform`. In Java and Kotlin it takes a `BiFunction<String, T, Object>` over the key and the value; in Scala it takes a `PartialFunction[(String, T), Any]` you define only for the keys you want changed, leaving the rest untouched. The JavaScript SDK takes a two-argument function.
  • What does Gatling do with the header line of a CSV feeder file?
    The first line supplies the Session attribute names for every record, and Gatling trims wrapping whitespace from each header field. A `jsonFile` feeder has no header: its root node must be a JSON array, and each object's own keys become the attribute names.

saying these in an interview costs you the question

  • Reading ssv as space-separated values; it is semicolon-separated.
  • Passing src/main/resources/data.csv as the feeder path instead of data.csv.
  • Calling a quotes method to set the quote character; only quoteChar exists.
  • Assuming sitemap comes from the core DSL rather than the HTTP DSL.
open as a page

A Gatling simulation declares csv("src/main/resources/credentials.csv") and dies before a single virtual user starts, although the file is exactly there. Why?

level: middleimportance: must knowfreq 55%

basics

~10 s

Gatling resolves a feeder path against the classpath, not the project tree, and specifically refuses paths starting src/main/resources/, src/test/resources/ or src/gatling/resources/. Use credentials.csv. The check runs while the Simulation constructor evaluates csv().

open as a page

A Gatling login simulation feeds from a 200,000-row credentials CSV. Does Gatling hold every row in heap, and what decides?

level: seniorimportance: should knowfreq 36%

basics

~20 s

It depends on file size. Gatling compares the uncompressed file length against gatling.core.feederAdaptiveLoadModeThreshold, 100 MB by default: below it the whole file is parsed into memory, above it records are read from disk as users consume them.

open as a page

A Gatling simulation calls csv("credentials.csv").readRecords() only to size its injection profile. What does that cost, and what should it call instead?

level: seniorimportance: should knowfreq 30%

basics

~20 s

readRecords builds the feeder and drains it into a list, so the file is parsed once for the sizing call and again when the run starts. recordsCount counts lines without constructing records, and is the call for sizing.

open as a page

A Gatling login simulation needs 200,000 distinct credentials per run. Would you ship them as a CSV, read them with jdbcFeeder, or serve them from Redis?

level: principalimportance: should knowfreq 32%

basics

~20 s

Default to the CSV. It is the only one of the three available in all five SDKs, it costs the running system nothing, and it ships with the artifact. Use the others only when the data cannot be a file.

open as a page

In Gatling's JavaScript and TypeScript SDK, which feeders and feeder methods from the JVM SDKs are missing?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

jdbcFeeder, redisFeeder in all four command forms, readRecords and the custom-iterator feeder are documented as not supported in the JavaScript and TypeScript SDK. The file and in-memory feeders, unzip, shard, transform and recordsCount all are.

open as a page