YAML Specification
Root sections
Every valid Relampo YAML script must include these sections at the same top level (root):
test(required): test metadata.variables(optional): reusable global variables.data_source(optional): external data input for the test.http_defaults(optional): default HTTP configuration.error_policy(optional): error handling behavior rules.scenarios(required): executable scenarios.
Main structure
test:
name: "My test"
description: "Optional"
version: "1.0"
variables:
base_url: "https://api.example.com"
username: "demo"
data_source:
type: csv
file: "users.csv"
mode: per_vu
http_defaults:
base_url: "{{base_url}}"
headers:
Accept: "application/json"
timeout: "30s"
follow_redirects: true
error_policy:
on_error: stop
on_4xx: continue
on_5xx: stop
scenarios:
- name: "Main"
load:
type: constant
users: 10
duration: 5m
ramp_up: 10s
iterations: 0
steps:
- get: /health
test
test defines script metadata.
Use it like this:
test:
name: "My test"
description: "Optional"
version: "1.0"
Common fields:
name(required): test name.description(optional): test description.version(optional): script version.
Notes:
nameis required to identify the test.
Variables
Variables let you reuse values across the script.
Use this syntax:
{{var}}
Example:
variables:
base_url: "https://api.example.com"
http_defaults:
base_url: "{{base_url}}"
Supported usage:
- URL
- headers
- query params
- body string
- body object (string fields)
Notes:
- If a variable does not exist, it is replaced with an empty string.
Data source
Data sources let you load external data to use in scenarios.
Types:
- csv
- txt
Supported configuration:
data_source:
type: csv
file: "/path/users.csv"
mode: per_vu # per_vu | shared | per_worker
strategy: sequential # sequential | random | unique
variable_names: "email,password"
# or bind in header-based mode
bind:
email_col: user_email
pass_col: user_password
on_exhausted: recycle # recycle | stop
Notes:
variable_namestreats all rows as data (no header).binduses first row as header.on_exhausted: stopstops that VU when the data source is exhausted.
Fields:
modeper_vu(default): each VU keeps its own cursor.shared: all VUs share a global cursor for the same file within a worker.per_worker: picks row by VU index (vu_idx), making row assignment stable per VU.
strategysequential(default): reads next row and advances cursor.random: picks a random row every iteration (no sequential cursor advance).unique: uses a shuffled order without repeating rows until dataset exhaustion.
variable_names- assigns columns by position (example:
email,password). - when present, all rows are treated as data (no header).
- missing columns are filled with empty string.
- assigns columns by position (example:
http_defaults
http_defaults is used to define global, reusable HTTP configuration for a scenario.
It is used to:
- Avoid repeating
base_url, headers, and timeouts on every request. - Set default redirect behavior.
- Control whether embedded resources are fetched and which types are allowed.
- Exclude embedded resources by pattern (for example analytics or hotjar).
Use it like this:
http_defaults:
base_url: "https://api.example.com"
headers:
User-Agent: "Relampo/1.0"
timeout: "30s"
follow_redirects: true
retrieve_embedded_resources: false
embedded_resource_types: ["js", "css", "img", "font"]
embedded_resource_blacklist: ["analytics", "hotjar"]
Field behavior:
timeout: "30s": maximum wait time per request. If exceeded, the request fails with timeout.follow_redirects: true: whentrue, Relampo follows HTTP redirects (301/302/307/308). Whenfalse, it returns the redirect response without following it.retrieve_embedded_resources: false: defines whether Relampo runs only the main request or also fetches embedded resources (js, css, images, fonts).false= main request only;true= main + embedded resources.embedded_resource_types: ["js", "css", "img", "font"]: allowlist of embedded resource types fetched whenretrieve_embedded_resourcesis enabled.embedded_resource_blacklist: ["analytics", "hotjar"]: list of substrings used to skip embedded URLs (case-insensitive match).
error_policy
error_policy defines behavior when request execution hits errors.
It can be defined at root, scenario, or request level.
Use it like this:
scenarios:
- name: "Main"
error_policy:
on_error: stop
on_4xx: continue
on_5xx: stop
on_timeout: stop
steps:
- get: /health
- request:
method: GET
url: /profile
error_policy:
on_4xx: stop
Supported fields:
on_erroron_4xxon_5xxon_timeout
Supported values:
stopcontinue
Override order:
- request-level
error_policyoverrides scenario-level. - scenario-level
error_policyoverrides root-level.
scenarios
scenarios defines executable flows in the test.
Use it like this:
scenarios:
- name: "Main"
load:
type: constant
users: 10
duration: 5m
cookies:
clear_each_iteration: true
policy: standard
cache_manager:
clear_each_iteration: true
max_elements: 1000
steps:
- get: /health
Inside each scenario you can define:
load: scenario load pattern.cookies: VU cookie behavior.cache_manager: HTTP cache behavior for requests.error_policy: scenario-level error behavior.steps: action flow executed by the scenario.
scenario.load
scenario.load defines how load is executed for that scenario.
Supported load types:
constantrampramp_up_downthroughput
Common behavior (applies to all 4 types):
- All types accept
durationanditerations. - If
iterations > 0, each VU runs exactly that number of iterations. - If
iterations = 0anddurationis set, it loops until duration ends. - If neither
durationnoriterationsis set, it runs once per VU.
constant
Use it like this:
load:
type: constant
users: 10
duration: 5m
ramp_up: 10s
ramp_down: 10s
iterations: 0
Behavior:
- Empty
typeis treated asconstant. usersdefines concurrent VUs.
ramp
Use it like this:
load:
type: ramp
start_users: 1
end_users: 50
duration: 10m
iterations: 0
Behavior:
- If
usersis missing or<= 1, it usesend_usersas total VUs. start_usersandend_usersare used to describe the linear load profile.
ramp_up_down
Use it like this:
load:
type: ramp_up_down
users: 50
duration: 10m
ramp_up: 2m
ramp_down: 1m
iterations: 0
Behavior:
- This pattern uses
users,duration,ramp_up, andramp_down. - It represents ramp up, steady phase, and ramp down.
throughput
Use it like this:
load:
type: throughput
target_rps: 20
duration: 10m
ramp_up: 1m
ramp_down: 1m
iterations: 0
Behavior:
target_rpsdefines the target requests per second for the whole scenario.- Relampo spaces executions to stay close to that RPS target.
durationkeeps that target active for the configured time window.- If
iterations > 0, the scenario ends when iterations complete, even if duration remains. ramp_upandramp_downcontrol ramp-in and ramp-out toward/from the target.
scenario.cookies
scenario.cookies controls how the scenario handles cookies.
Use it like this:
scenarios:
- name: "Main"
cookies:
policy: standard
clear_each_iteration: false
cookies:
- name: session_id
value: abc123
domain: api.example.com
path: /
Behavior:
policysupportsstandardandignore_cookies.clear_each_iteration: trueresets cookie jar on each iteration;falsekeeps it.cookies[]lets you preload initial cookies (name,value,domain,path).
scenario.cache_manager
scenario.cache_manager enables HTTP response caching in the scenario.
Use it like this:
scenarios:
- name: "Main"
cache_manager: {}
- With
cache_manageractive, successfulGETrequests (status < 400) are cached by full URL. - At request level,
cache_overridecan forceenabledordisabled, and it overrides scenario-level behavior.
scenario.steps
scenario.steps defines the actions each virtual user executes inside the scenario.
Currently supported step types:
- HTTP requests:
request,get,post,put,delete,patch,head,options - Flow control:
if,loop,retry - Organization and measurement:
group - Validation:
assertions - Pauses:
think_time
Execution behavior:
stepsrun in order, top to bottom.- If a step contains nested
steps, that block runs first, then flow continues.
step.request
step.request defines an HTTP call inside the flow.
1. When to use short vs long form
- Use short form (
get,post,put,delete,patch,head,options) when you only need a simple call. - Use long form (
request) when you need details likeheaders,body,assertions,extractors,timeout,files, orerror_policy.
2. Minimal request
steps:
- request:
method: GET
url: /health
3. What it inherits and overrides
- It inherits from
http_defaults(for examplebase_url, headers, and timeout). - Values declared inside the request override global defaults.
4. step.request subsections
The following blocks are part of step.request and are documented as separate quick-reference sections.
step.request.headers
headers defines request-specific HTTP headers.
Use it like this:
- request:
method: GET
url: /me
headers:
Authorization: "Bearer {{token}}"
Accept: "application/json"
Behavior:
- It is a
key: valueobject. - Values are interpolated with variables.
- If a header also exists in
http_defaults.headers, request-level value overrides it.
step.request.query_params
query_params adds parameters to the final request query string.
Use it like this:
- request:
method: GET
url: /search
query_params:
q: "relampo"
page: "1"
Behavior:
- It is a
key: valueobject. - Values are interpolated with variables.
- They are applied on top of the resolved request URL.
step.request.body
body defines the request HTTP payload.
Use it like this:
- request:
method: POST
url: /login
body:
user: "{{username}}"
pass: "{{password}}"
Supported types and behavior:
string: sent as literal string (interpolated).object: serialized as JSON; string fields are interpolated.- Other types: JSON marshaling is attempted.
- If
Content-Typeis not set and body is serialized as JSON, Relampo setsapplication/json.
step.request.timeout
timeout sets a request-specific timeout.
Use it like this:
- request:
method: GET
url: /reports
timeout: "45s"
Behavior:
- Uses duration format (
500ms,5s,1m). - If invalid, it falls back to client/global timeout.
step.request.enabled
enabled lets you turn a request on/off.
Use it like this:
- request:
method: GET
url: /experimental
enabled: false
Behavior:
false: request is skipped.trueor missing: request executes normally.
step.request.assertions
Inside step.request, validations can be defined in two formats: assert and assertions.
Use them like this:
- request:
method: GET
url: /health
assert:
status: 200
body_contains: "ok"
- request:
method: GET
url: /health
assertions:
- type: status
value: 200
- type: contains
value: "ok"
Supported types and behavior:
assert(object format): direct keys such asstatus,status_in,body_contains,body_not_contains,body_matches,response_time_ms,jsonpath,json,header,response_size.assertions(list): supportsstatus,contains,not_contains,regex,jsonpath,json,header,response_time,response_time_max,response_size.
Assertion types (in assertions):
status: validates expected HTTP status code.contains/not_contains: validates presence or absence of text in response body.regex: validates response body with a regular expression.jsonpath/json: validates a JSON value by path.header: validates a response header value.response_time/response_time_max: validates response time.response_size: validates response size.
step.request.extractors
Inside step.request, extractors can be defined in two formats: extract and extractors.
Use them like this:
- request:
method: POST
url: /login
extract:
token: "jsonpath($.token)"
req_id: "header.X-Request-Id"
- request:
method: POST
url: /login
extractors:
- type: jsonpath
var: token
expression: $.token
default: ""
- type: regex
var: order_id
pattern: "orderId=(\\w+)"
capture_mode: first
Supported types and behavior:
extract(simple object format): supportsbody,header.<Name>,regex("..."),jsonpath(...).extractors(list): supportsheader,body,jsonpath(aliasjson),xpath,boundary,regex.
Extractor types (in extractors):
regex: extracts values with a regular expression frombody,headers, orstatus_linedepending onfrom.jsonpath/json: extracts values from JSON responses usingexpressionorpath.header: extracts the value of a specific response header.xpath: extracts values from XML/HTML responses using XPath.boundary: extracts text betweenleft_boundaryandright_boundary.
Behavior options:
fromsupportsbody,headers,status_line.capture_modesupportsfirst,all,index,random.defaultlets you assign a fallback value when no match is found.
step.request.files
files enables multipart uploads.
Use it like this:
- request:
method: POST
url: /upload
body:
category: invoices
files:
- field: file
path: /tmp/invoice.pdf
mime: application/pdf
Supported types and behavior:
- Each file entry uses
field,path, and optionalmime. - If
filesis present, request is sent asmultipart/form-data.
step.request.error_policy
error_policy sets error behavior only for that request.
Use it like this:
- request:
method: GET
url: /profile
error_policy:
on_error: stop
on_4xx: continue
on_5xx: stop
on_timeout: stop
Supported values and behavior:
- Supported values:
stopandcontinue. - Can define
on_error,on_4xx,on_5xx,on_timeout. - At request level, it overrides
scenario.error_policy.
step.request.cache_override
cache_override lets a request override scenario-level cache behavior.
Use it like this:
- request:
method: GET
url: /catalog
cache_override: enabled
Supported values:
- Supported modes:
inherit,enabled,disabled. cache_overridecontrols request-level HTTP cache behavior.
step.request.cookie_override
cookie_override lets a request override scenario-level cookie behavior.
Use it like this:
- request:
method: GET
url: /catalog
cookie_override: disabled
Supported values:
- Supported modes:
inherit,enabled,disabled. cookie_overridecontrols whether the request uses cookie jar.
step.request.redirects
follow_redirects and redirect_automatically control redirects at request level.
Use it like this:
- request:
method: GET
url: /old-path
follow_redirects: false
Behavior:
- Both are booleans.
- Precedence:
redirect_automatically>follow_redirects>http_defaults.follow_redirects. - If effective value is
false, Relampo does not follow redirects and returns the 3xx response.
step.request.retrieve_embedded_resources
retrieve_embedded_resources enables/disables embedded resource fetching for that request.
Use it like this:
- request:
method: GET
url: /home
retrieve_embedded_resources: true
Behavior:
- Boolean at request level.
- Evaluated only for successful
GETresponses (status < 400) with HTML/CSS content. - Uses resource types and blacklist from
http_defaults.
step.request.spark
spark runs JavaScript scripts before or after request execution.
Use it like this:
- request:
method: GET
url: /profile
spark:
- when: before
script: |
vars.set("trace_id", "abc-123")
- when: after
script: |
if (response.status === 200) {
vars.set("ok", true)
}
Supported values and behavior:
whensupportsbeforeandafter(defaults toafterwhen omitted).scriptaccepts JavaScript.- Primary goal: transform values and generate dynamic variables for subsequent steps.
- Available context:
vars.get,vars.set,log. responseexists only inafter(status,body,latency_ms).
Example (split a value and store a variable):
- request:
method: POST
url: /login
spark:
- when: after
script: |
var payload = JSON.parse(response.body || "{}");
var session = String(payload.session_id || "");
var parts = session.split("-");
vars.set("session_prefix", parts[0] || "");
Example (normalize response data into a reusable variable):
- request:
method: GET
url: /profile
spark:
- when: after
script: |
var payload = JSON.parse(response.body || "{}");
var user = payload.user || {};
var email = String(user.email || "");
if (email) {
vars.set("email_lower", email.toLowerCase());
}
step.control_flow
step.control_flow controls branching, repetition, and retries inside steps.
Currently supported control flow steps:
ifloopretry
Example:
steps:
- if: "{{token}} != ''"
steps:
- get: /profile
- loop:
count: 3
break_on: "{{done}} == true"
steps:
- get: /poll
- retry:
attempts: 3
backoff: exponential
initial_delay: 1s
max_delay: 10s
multiplier: 2
steps:
- get: /health
Behavior:
ifruns nestedstepsonly when the condition evaluates to true.looprepeats nestedstepsbased oncount(or untilbreak_onis true).retryreruns nestedstepsuntil success or attempts are exhausted.
Common fields:
if: condition +steps.loop:count,break_on,steps.retry:attempts,backoff,initial_delay,max_delay,multiplier,steps.
step.group
step.group groups related steps under a named block.
Use it like this:
steps:
- group:
name: "Login Flow"
steps:
- post: /login
- get: /profile
step.assertions
step.assertions validates the most recent response inside the flow.
Example:
steps:
- get: /health
- assertions:
- type: status
value: 200
- type: contains
value: "ok"
- type: response_time
value: "<800"
Behavior:
- It always evaluates against the immediately previous response.
- If there is no previous response, the step fails.
Supported assertion types:
status: validates that the HTTP status code exactly matches the expected value (for example200).contains/not_contains: validates whether response body includes or excludes text.regex: validates response body with a regular expression.jsonpath/json: validates existence or value at a JSON path (for example$.data.id).header: validates that a header exists or has a specific value.response_time/response_time_max: validates response time with comparisons like<800or>200.response_size: validates response body size.
step.think_time
step.think_time adds a pause between actions to simulate real user timing.
Supported types:
fixed: fixed pause withduration(or short formthink_time: 2s).uniform: uniform random pause betweenminandmax.normal: normal random pause usingmeanandstd_dev(clamped bymin/maxwhen provided).
steps:
- get: /health
- think_time: 2s
steps:
- think_time:
min: 1s
max: 3s
distribution: uniform
steps:
- think_time:
mean: 2s
std_dev: 500ms
min: 1s
max: 4s
distribution: normal
Behavior:
- If you use
duration(or short formthink_time: 2s), that value takes precedence. - If
durationis missing, it usesmin/maxrange (uniformdistribution by default). - If
distribution: normal, it usesmeanandstd_dev, then clamps bymin/maxwhen provided. - If no valid time values are provided, no pause is applied.
Common fields:
duration: fixed pause.min/max: pause range.distribution:uniformornormal.mean/std_dev: used for normal distribution.
scenarios is required and must include at least one scenario.