Skip to main content

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:

  • name is 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_names treats all rows as data (no header).
  • bind uses first row as header.
  • on_exhausted: stop stops that VU when the data source is exhausted.

Fields:

  • mode
    • per_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.
  • strategy
    • sequential (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.

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: when true, Relampo follows HTTP redirects (301/302/307/308). When false, 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 when retrieve_embedded_resources is 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_error
  • on_4xx
  • on_5xx
  • on_timeout

Supported values:

  • stop
  • continue

Override order:

  • request-level error_policy overrides scenario-level.
  • scenario-level error_policy overrides 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:

  • constant
  • ramp
  • ramp_up_down
  • throughput
  • stages

Common behavior:

  • All types accept duration and iterations.
  • If iterations > 0, each VU runs exactly that number of iterations.
  • If iterations = 0 and duration is set, it loops until duration ends.
  • If neither duration nor iterations is 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 type is treated as constant.
  • users defines concurrent VUs.

ramp

Use it like this:

load:
type: ramp
start_users: 1
end_users: 50
duration: 10m
iterations: 0

Behavior:

  • If users is missing or <= 1, it uses end_users as total VUs.
  • start_users and end_users are 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, and ramp_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_rps defines the target requests per second for the whole scenario.
  • Relampo spaces executions to stay close to that RPS target.
  • duration keeps that target active for the configured time window.
  • If iterations > 0, the scenario ends when iterations complete, even if duration remains.
  • ramp_up and ramp_down control ramp-in and ramp-out toward/from the target.

stages

Use it like this:

load:
type: stages
duration: 10m
stages:
- type: constant
users: 5
duration: 2m
- type: ramp_up
start_users: 5
end_users: 20
duration: 3m
- type: ramp_down
start_users: 20
end_users: 0
duration: 5m

Behavior:

  • duration is required at load level.
  • stages must be a non-empty list.
  • Stage type supports constant, ramp_up, and ramp_down.
  • Stage durations must cover the full load.duration without gaps or overlap.
  • Only the last stage can use open_ended: true; an open-ended stage omits its own duration and uses the remaining load.duration.
  • load.type: stages does not support mixing users, start_users, end_users, ramp_up, ramp_down, iterations, target_rps, target_unit, target_value, min_vus, max_vus, or aggressiveness at the same load level.

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:

  • policy supports standard and ignore_cookies.
  • clear_each_iteration: true resets cookie jar on each iteration; false keeps 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_manager active, successful GET requests (status < 400) are cached by full URL.
  • At request level, cache_override can force enabled or disabled, 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
  • Data and database: data_source, sql
  • Containers and controllers: group, controller, transaction, parallel, one_time, balanced
  • Flow control: if, loop, retry
  • Validation: assertions
  • Pauses: think_time

Execution behavior:

  • steps run 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 like headers, body, assertions, extractors, timeout, files, or error_policy.

2. Minimal request

steps:
- request:
method: GET
url: /health

3. What it inherits and overrides

  • It inherits from http_defaults (for example base_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: value object.
  • 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: value object.
  • 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-Type is not set and body is serialized as JSON, Relampo sets application/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.
  • true or 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 as status, status_in, body_contains, body_not_contains, body_matches, response_time_ms, jsonpath, json, header, response_size.
  • assertions (list): supports status, 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): supports body, header.<Name>, regex("..."), jsonpath(...).
  • extractors (list): supports header, body, jsonpath (alias json), xpath, boundary, regex.

Extractor types (in extractors):

  • regex: extracts values with a regular expression from body, headers, or status_line depending on from.
  • jsonpath / json: extracts values from JSON responses using expression or path.
  • header: extracts the value of a specific response header.
  • xpath: extracts values from XML/HTML responses using XPath.
  • boundary: extracts text between left_boundary and right_boundary.

Behavior options:

  • from supports body, headers, status_line.
  • capture_mode supports first, all, index, random.
  • default lets 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 optional mime.
  • If files is present, request is sent as multipart/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: stop and continue.
  • 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_override controls 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_override controls 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 GET responses (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:

  • when supports before and after (defaults to after when omitted).
  • script accepts JavaScript.
  • Primary goal: transform values and generate dynamic variables for subsequent steps.
  • Available context: vars.get, vars.set, log.
  • response exists only in after (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:

  • if
  • loop
  • retry

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:

  • if runs nested steps only when the condition evaluates to true.
  • loop repeats nested steps based on count (or until break_on is true).
  • retry reruns nested steps until 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

Common fields:

  • name: optional label.
  • enabled: optional boolean. When false, the group is skipped.
  • auth: optional auth override inherited by child steps.
  • steps: child steps executed in order.

step.controller

step.controller is a generic container for nested steps. It behaves like a named block that can hold requests, assertions, think time, data sources, or other controllers.

Use it like this:

steps:
- controller:
name: "Checkout Flow"
steps:
- get: /cart
- post: /checkout

Common fields:

  • name: optional label.
  • enabled: optional boolean. When false, the controller is skipped.
  • auth: optional auth override inherited by child steps.
  • steps: child steps executed in order.

step.transaction

step.transaction groups nested steps and records transaction-level metrics. Use it when a business action should be measured as one unit, such as login, checkout, or search.

Use it like this:

steps:
- transaction:
name: "Login"
steps:
- get: /login
- post:
url: /session
body:
user: "{{username}}"
password: "{{password}}"

Common fields:

  • name: transaction name shown in reports.
  • enabled: optional boolean. When false, the transaction is skipped.
  • auth: optional auth override inherited by child steps.
  • steps: child steps executed in order.

step.parallel

step.parallel executes child steps concurrently inside the same VU flow. Each branch receives an isolated copy of the current variables, and changed variables are merged back after branches finish.

Use it like this:

steps:
- parallel:
name: "Load dashboard widgets"
steps:
- get: /api/widget-a
- get: /api/widget-b
- get: /api/widget-c

Use it for independent requests that should happen at the same logical time.

Common fields:

  • name: optional label.
  • enabled: optional boolean. When false, the parallel block is skipped.
  • auth: optional auth override inherited by child steps.
  • steps: child steps executed concurrently.

step.one_time

step.one_time runs initialization steps once for the scenario execution and reuses generated variables for later VUs or iterations.

Use it like this:

steps:
- one_time:
name: "Authenticate once"
steps:
- post:
url: /login
body:
user: "{{admin_user}}"
password: "{{admin_password}}"
extractors:
- type: jsonpath
var: admin_token
path: $.token

- get:
url: /admin/me
headers:
Authorization: "Bearer {{admin_token}}"

Common fields:

  • name: optional label.
  • description: optional description.
  • enabled: optional boolean. When false, the one-time block is skipped.
  • auth: optional auth override inherited by child steps.
  • steps: initialization steps.

step.balanced

step.balanced routes each VU or iteration into one child branch based on percentage distribution.

Use it like this:

scenarios:
- name: "Traffic mix"
load:
type: constant
users: 10
iterations: 20
steps:
- balanced:
name: "Traffic Mix"
type: total
mode: iterations
steps:
- percentage: 70
transaction:
name: "Browse"
steps:
- get: /products
- percentage: 30
transaction:
name: "Checkout"
steps:
- get: /cart
- post: /checkout

Rules:

  • name is required.
  • type must be total.
  • mode must be iterations or virtual_users.
  • Participating child steps must include percentage.
  • Percentages must sum exactly to 100.
  • Child branches must contain at least one enabled HTTP request or SQL step.
  • mode: iterations requires load.iterations greater than 0, unless the scenario is a simple one-shot functional run.
  • mode: virtual_users is not supported with dynamic user loads such as stages or intent.

Supported child step types inside balanced:

  • request and HTTP short forms
  • sql
  • group
  • controller
  • transaction
  • if
  • loop
  • retry

step.data_source

step.data_source can load data at a specific point in the flow. It uses the same data source behavior as the root-level data_source block, but the binding happens when the step executes.

Use it like this:

steps:
- data_source:
type: csv
file: users.csv
mode: shared
variable_names: email,password
on_exhausted: recycle

- post:
url: /login
body:
email: "{{email}}"
password: "{{password}}"

Supported source types:

  • csv
  • txt

Supported modes:

  • per_vu
  • shared
  • per_worker

Supported strategies:

  • sequential
  • random
  • unique

Notes:

  • variable_names can be a comma-separated string or a YAML list.
  • bind uses a header row and maps source columns to variable names.
  • A step-level data_source keeps an independent cursor from other data source nodes.
  • on_exhausted: stop ends the current VU iteration gracefully when data is exhausted.

step.sql

step.sql executes a database query or command as part of a scenario.

Use it like this:

steps:
- sql:
name: "Check user count"
dialect: postgres
kind: query
connection:
host: localhost
port: 5432
database: app
user: "{{db_user}}"
password: "{{db_password}}"
ssl_mode: disable
query: "select count(*) from users"

Supported dialects:

  • postgres
  • mysql

Supported kinds:

  • query: read operation.
  • exec: write operation. Requires allow_writes: true.

Required connection fields:

  • host
  • database
  • user
  • password

Common optional fields:

  • name
  • params
  • timeout
  • validate_connectivity
  • on_error
  • error_policy
  • connection.port
  • connection.ssl_mode
  • connection.max_open_conns
  • connection.max_idle_conns
  • connection.conn_max_lifetime

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 example 200).
  • 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 <800 or >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 with duration (or short form think_time: 2s).
  • uniform: uniform random pause between min and max.
  • normal: normal random pause using mean and std_dev (clamped by min/max when 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 form think_time: 2s), that value takes precedence.
  • If duration is missing, it uses min/max range (uniform distribution by default).
  • If distribution: normal, it uses mean and std_dev, then clamps by min/max when provided.
  • If no valid time values are provided, no pause is applied.

Common fields:

  • duration: fixed pause.
  • min / max: pause range.
  • distribution: uniform or normal.
  • mean / std_dev: used for normal distribution.

scenarios is required and must include at least one scenario.