Chapter 06Lesson 03120–160 min

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.

DesignVariable filesMutationTypingConfiguration

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?

When is a Python variable file preferable to a simple Variable section?

Why convert an environment worker count to int near the boundary?

Does global scope make a value easier to override safely?

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.

Next lesson

Variables: Scalar, List, Dictionary, Environment, and Dynamic Values: Diagnostics, Failure Modes, and Production Practices

Continue with Variables: Scalar, List, Dictionary, Environment, and Dynamic Values: Diagnostics, Failure Modes, and Production Practices. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

Further reading

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.