Variables: Scalar, List, Dictionary, Environment, and Dynamic Values: Configuration, Design Patterns, and Trade-Offs
Choose variable sources and scopes deliberately so configuration stays portable, mutable containers do not become hidden shared state, and type/secret boundaries remain explicit.
Learning objectives
- Select local, test, suite, suites, or global scope based on ownership and lifetime rather than convenience.
- Choose among Variable sections, variable files, command-line inputs, and environment inputs for different configuration needs.
- Recognize aliasing and shared mutation when lists/dictionaries are reused across scopes.
- Decide when typed conversion should occur and avoid relying on accidental string behavior.
- Apply naming and secret-handling conventions that improve CI diagnostics without exposing sensitive values.
Current compatibility baseline. Verified
2026-08-31: Robot Framework 7.4.2 is the stable release used by this
chapter and requires Python 3.8+. Robot Framework 7.5b1 is a
pre-release and is not required. Native VAR has existed
since 7.0; scope=SUITES since 7.1; variable type
conversion such as ${count: int} is stable since 7.3;
and Secret variables are stable since 7.4.
1. Start with ownership, not syntax
A variable mechanism is a design choice. Ask who owns the value,
when it should change, whether callers should be able to override
it, whether it is sensitive, and how long it should remain visible.
Only then choose Variable section, variable file, CLI, environment,
or runtime VAR.
| Need | Preferred starting point | Why |
|---|---|---|
| Small committed suite constant | Variable section | Close to the suite, reviewable, simple. |
| Structured/dynamic environment configuration | Variable file | Can create Python/YAML-derived objects and compute values deliberately. |
| CI-selected non-secret profile | --variable / argument file |
Explicit run-time startup configuration with high priority. |
| Secret supplied by runner/OS | Environment/secret provider → Secret conversion | Keeps real value out of committed test data; masking can begin at Robot boundary. |
| Temporary keyword computation | Local assignment / VAR |
Narrow lifetime and clear ownership. |
2. Narrow scope is the default production pattern
Local variables are easiest to reason about because they cannot
unexpectedly affect a later test. Test scope is appropriate for a
correlation ID or fixture handle shared by keywords in one scenario.
Suite scope can represent suite-owned setup state, but mutation
affects later cases and therefore requires stronger teardown and
ordering discipline. SUITES and
GLOBAL expand the blast radius further.
Global scope is appropriate for truly global startup configuration, but runtime global mutation is rarely the cleanest way to communicate between test cases. Shared external stores or explicit return values usually make ownership clearer.
3. Variable section versus variable files
Variable sections are declarative and easy to review. Python variable files can return arbitrary objects and calculate values; YAML variable files need PyYAML and add a dependency. Dynamic power should be used where it solves a real configuration problem, not to hide initialization logic.
# variables/dev.py
STAGE = "dev"
BASE_URL = "http://127.0.0.1:8080"
LIMITS = {"workers": 2, "timeout": 5}
# run
python -m robot --variablefile variables/dev.py suites/
Keep paths relative to stable project structure rather than the
caller’s accidental current directory. Use ${CURDIR} or
a documented project-root convention when imports must be
file-relative.
4. Mutable list/dict sharing: alias versus copy
Robot variables can hold real Python containers. If two variables refer to the same list or dictionary object, mutating through one reference changes the object seen through the other. Scope does not automatically clone the value.
*** Settings ***
Library Collections
*** Test Cases ***
Aliasing Hazard
VAR @{base} alpha beta
VAR ${alias} ${base}
Append To List ${alias} gamma
# ${base} now also refers to the mutated list object.
When independent state is required, create a copy with an appropriate collection/library mechanism instead of assuming assignment copied the container. In parallel suites, also remember that each worker process has its own Python memory while shared files/databases/services remain genuinely shared.
5. Convert at trust boundaries
A value supplied by CLI or environment is text unless converted.
Convert where the suite first requires a semantic type. That gives
failures a useful location and prevents subtle comparisons such as
string "10" versus integer 10.
*** Variables ***
${DEFAULT_WORKERS: int} 2
*** Test Cases ***
Configuration Boundary
VAR ${workers: int} %{RF_WORKERS=2}
Should Be True $workers > 0
Do not annotate every value. IDs, postal codes, version strings, and values with leading zeros may be intentionally textual even when they contain digits.
6. Secret-handling design
Secret conversion can reduce accidental exposure in Robot logs, but
it does not solve acquisition, storage, rotation, authorization, or
downstream-library logging. Keep the secret source outside committed
files, convert to Secret early when compatible, and
pass it only through APIs that preserve masking.
| Pattern | Risk | Safer direction |
|---|---|---|
Hard-code real token in *** Variables ***
|
Repository disclosure | Read from runner secret store/environment. |
| Pass secret directly on CLI text | Shell history / process logs | Use runner-protected environment or secret injection. |
Access ${SECRET.value} in test data |
Reveals the real value to Robot/logging | Let a Secret-aware library consume the object. |
| Assume Secret encrypts memory | False security boundary | Treat process/API access as privileged. |
7. Naming conventions expose intended scope
The Robot Framework style guide recommends uppercase names for global and broader-scope variables and lowercase for local variables. This is convention, not parser enforcement, but it helps reviewers see whether a keyword is using local computation or wider configuration.
Context can override casing conventions when matching an external API schema is more readable. Consistency and ownership matter more than mechanically forcing every identifier into one shape.
8. Worked scenario: promotion across environments
| Requirement | Choice | Trade-off |
|---|---|---|
| Same tests run local/integration/staging | CLI variable file or profile | Explicit at startup; easy CI provenance. |
| Per-test synthetic account ID | Test scope | Visible to all keywords in test, isolated from next test. |
| Reusable default retry count | Suite Variable section, typed int | Reviewable and typed; CLI can override if intended. |
| OAuth token | Runner secret → environment → Secret | Better log safety, but downstream library must be Secret-aware. |
| Mutable expected-items list | Local copy per test | Avoids cross-test contamination. |
9. Knowledge check
Why can assigning a suite list to a local scalar still create shared-state risk?
Both variables may reference the same mutable Python list object; changing the object through either reference is visible to the other.
When is a Python variable file preferable to a simple Variable section?
When configuration needs dynamic computation, complex objects, or a reusable structured source that justifies executable Python.
Why convert an environment worker count to int near the boundary?
It turns invalid external text into an immediate, diagnosable configuration failure and avoids accidental string semantics.
Does global scope make a value easier to override safely?
No. It increases visibility and coupling; override behavior depends on priority and runtime definitions, not “importance.”
10. Summary and next step
Variable design is configuration architecture: narrow scopes reduce coupling, source choice communicates ownership, typed conversion belongs at semantic boundaries, mutable containers require explicit copying, and Secret is only one logging safeguard. Lesson 4 applies these rules to realistic failures and diagnosis.
Further reading
- Robot Framework 7.4.2 User Guide — Variables — scalar/list/dictionary/environment syntax, creation mechanisms, priorities, scopes, typed conversion, and Secret values.
- Robot Framework 7.4.2 User Guide — Variable priorities and scopes — static priority and runtime scope rules.
- Robot Framework 7.4.2 User Guide — VAR syntax — local/test/task/suite/suites/global scope configuration.
- Robot Framework 7.4.2 User Guide — Variable type conversion — stable typed variable creation introduced in 7.3.
- Robot Framework 7.4.2 User Guide — Secret variables — masking semantics and security limitations introduced in 7.4.
- Robot Framework Style Guide — casing and scope-oriented naming conventions.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.