Variables are how Bruno keeps your API collections flexible. Instead of hard-coding a base URL, a token, or a timeout in every request, you define a variable once and reference it everywhere. Bruno v4 takes this further: variables can now be typed. A timeout can be a number, a feature flag can be a boolean, and a config block can be a full object not just strings. This guide covers the full variable system in Bruno and dives into the typed variable support introduced in v4, including the breaking change you need to know about before upgrading.
Table of Contents
A variable is a named value that Bruno substitutes into your requests at runtime. You reference a variable using double curly braces:
https://{{baseUrl}}/users/{{userId}}
When Bruno runs that request, {{baseUrl}} and {{userId}} are replaced with their current values. If you change the base URL for staging, you update it in one place instead of every request that uses it.
Variables can appear in:
Bruno has eight distinct variable categories. Each has a different scope and a different place it is defined:
| Variable Type | Where It Is Defined | Typical Use |
|---|---|---|
| Global Environment | Global environment settings | Values shared across all collections |
| Environment | <env-name>.yml |
Base URLs, tokens per environment (dev / staging / prod) |
| Collection | opencollection.yml |
Defaults that apply to all requests in the collection |
| Folder | <folder-name>.yml |
Shared values for a group of related requests |
| Request | <request-name>.yml |
Values specific to a single request |
| Runtime | Set in scripts at runtime | Passing data between requests in a sequence |
| Prompt | syntax |
Values you type in at the moment of each run (never stored) |
| Process Environment | External .env file |
Injecting CI/CD or OS environment variables via |
Breaking change in v4.0.0: Bruno now supports typed variables. Collections that use @type(...) annotations will not parse in Bruno versions older than v4.0.0. If your team has members on v3, coordinate the upgrade before using typed variables in shared collections.
Before v4, every variable was a string. That meant sending a timeout value of 30 in a JSON body would arrive as "30" (a string) instead of the number 30. You had to cast it in a script. v4 removes that limitation.
Starting with v4.0.0, variables support four data types:
"text"
string
Default. No annotation needed.
42
number
Integers and decimals. Use @number
true
boolean
Feature flags, toggles. Use @boolean
{...}
object
Config blocks, nested data. Use @object
| Type | Annotation | Example value | Works across |
|---|---|---|---|
| string | none required | https://api.example.com |
All variable scopes |
| number | @number |
30 |
All variable scopes |
| boolean | @boolean |
true |
All variable scopes |
| object | @object |
{ "host": "localhost" } |
All variable scopes |
Backward compatible: Existing .bru files and environments that use plain string values continue to work without any changes. The @type annotation is only written when a non-string type is used.
In .yml files (used for workspace-level and environment configs), each typed variable is an object with a type field and a data field. Plain strings continue to use the flat name: value form — no change needed there.
number and boolean
runtime:
variables:
- name: timeout
value:
type: number
data: "30"
- name: debug
value:
type: boolean
data: "true"
object and plain string
- name: config
value:
type: object
data: '{"host":"localhost","port":8080}'
- name: baseUrl
value: https://api.example.com
# plain string — no type field needed
BRU vs YAML at a glance
| Aspect | BRU format | YAML format |
|---|---|---|
| Type declaration | Annotation on the line above: @number |
type: number field inside the value object |
| Object values | Triple-quote block '''...''' |
Inline JSON string: '{"key":"val"}' |
| Plain string | No annotation; just key: value |
Flat value: the-string |
In .bru files, you declare a type by placing the annotation on the line immediately above the variable. Object values use a triple-quote (''') block to hold multi-line JSON.
number and boolean
vars:pre-request {
@number
timeout: 30
@boolean
debug: true
baseUrl: https://api.example.com
}
object (triple-quote block)
vars:pre-request {
@object
config: '''
{
"host": "localhost",
"port": 8080
}
'''
}
A full pre-request vars block combining all four types looks like this:
vars:pre-request {
baseUrl: https://api.example.com // string — no annotation
@number
timeout: 30
@boolean
featureFlag: true
@object
dbConfig: '''
{
"host": "localhost",
"port": 5432
}
'''
}
The annotation must be on the line immediately above the variable, with no blank line between them. A blank line between @number and the variable name will cause it to be treated as a string.
You can set typed variables from pre-request and post-request scripts using the same scripting API you already know. Bruno infers the type from the JavaScript value you pass and writes the correct annotation automatically — you do not need to specify a type manually.
// number — written with @number annotation
bru.setEnvVar("timeout", 30)
// boolean — written with @boolean annotation
bru.setEnvVar("debug", true)
// object — written with @object annotation
bru.setEnvVar("config", { host: "localhost", port: 8080 })
// string — written as plain string (no annotation)
bru.setEnvVar("baseUrl", "https://api.example.com")
When Bruno reads the variable back on the next request run, timeout resolves as a JavaScript number and config resolves as an object — not strings that need parsing. The type is preserved across runs.
Typed values work across all variable scopes from scripts. The same inference applies to:
Environment variables
bru.setEnvVar("retries", 3)
bru.setEnvVar("verbose", false)
Runtime variables
bru.setVar("userId", 101)
bru.setVar("isAdmin", true)
Debugging variables in the console
To inspect a variable value and its resolved type during a run, use the bru.get[Type]Var(key) pattern in a script:
// Runtime variable
console.log(bru.getVar('userId'))
// Environment variable
console.log(bru.getEnvVar('timeout'))
// Collection variable
console.log(bru.getCollectionVar('config'))
Prompt variables are not accessible via the Scripting API. They are entered by the user at the moment of the run and are never stored or readable from scripts.
You do not need to write annotations by hand. In the Vars tab of any request, folder, or environment, each variable row has a type dropdown to the right of the value field. Changing the type in the dropdown writes the correct annotation into the .yml file automatically.
Available options in the dropdown match the four supported types: string, number, boolean, and object. When you select object, the value field expands to accept a JSON block.
| Topic | Details |
|---|---|
| Variable types (categories) | Global, Environment, Collection, Folder, Request, Runtime, Prompt, Process Env |
| Supported data types (v4+) | string (default), number, boolean, object |
| BRU annotation placement | Line immediately above the variable: @number, @boolean, @object |
| YAML type declaration | value: { type: number, data: "30" } |
| Breaking change | Files with @type annotations will not parse in Bruno < v4.0.0 |
| Script type inference | bru.setEnvVar("key", 30) infers number automatically |
| Environment color coding | Available since v3.1.0 — brush icon in environment settings |
| Documentation | Variables Overview |
Variables are the foundation of any well-organised Bruno collection. They keep values in one place, let you switch environments instantly, and flow data between requests through scripts. Bruno v4 extends this with real data types: numbers stay numbers, booleans stay booleans, and objects stay objects — from the file on disk all the way through to the request body, without any casting or parsing in scripts.
The one thing to coordinate before adopting typed variables is the team upgrade: any .bru file with a @number, @boolean, or @object annotation will not open in Bruno versions before v4. Once your team is on v4, you get the full power of typed variables across all scopes, in both the BRU and YAML formats, and with automatic type inference from scripts.