skip to content

Resolution Order

What happens when the same name sits in more than one store: a fixed walk, the first match winning, and a disabled entry treated as absent. The most asked and most mis-stated fact here.

part ofAPI & DB clientsoverview, primer and where to startread it →
on this pageshow

explore

questions

4

When several Postman stores define the same variable name, which value does pm.variables.get return?

level: juniorimportance: must knowfreq 68%

answer

  1. Precedence is not a stored priority field
  2. The scope carries layers, walked in turn
  3. Local values sit above every layer
  4. Iteration data, environment, collection, then globals

basics

~10 s

pm.variables walks a fixed chain and returns the first non-disabled match: its own local values, then iteration data, then the environment, then collection variables, then globals. An environment value therefore beats a collection variable.

solid answer

~40 s

`pm.variables` is not a store of its own. It is a `VariableScope` — an SDK class — that the sandbox builds with layers attached in a fixed order: `addLayer` is called with the iteration data list, then the environment's values, then the collection variables' values, then the globals' values. The scope's own `values` hold the local variables. `VariableScope.get` looks in its own values first, then walks `_layers` front to back and returns the first entry that exists and is not disabled. So a name defined in both the environment and the collection resolves to the environment's value, and a global answers only when nothing nearer defines the name. Nothing consults a priority field — precedence is simply the push order — and if the walk finds nothing, `get` returns `undefined`.

code

javascript · 12 lines
javascript
pm.collectionVariables.set('baseUrl', 'https://from-collection.example');
pm.environment.set('baseUrl', 'https://from-environment.example');

// the walk is local values -> data -> environment -> collection -> globals
console.log(pm.variables.get('baseUrl')); // https://from-environment.example

// addressing one store skips the walk
console.log(pm.collectionVariables.get('baseUrl')); // https://from-collection.example

// a local value is checked before any layer
pm.variables.set('baseUrl', 'https://local.example');
console.log(pm.variables.get('baseUrl')); // https://local.example

go deeper

for a junior

Be ready to name the chain out loud in order and say that the first match ends the search. Knowing that an environment value beats a collection variable of the same name is the expected takeaway.

for a middle

Explain the mechanism, not just the order: pm.variables is a scope with layers pushed in a fixed sequence, and get walks its own values first, then those layers, returning the first non-disabled hit.

for a senior

Show how you diagnose a shadowed value in a real run: compare what pm.variables reports against what each single store reports, and identify which layer actually answered rather than guessing.

for a principal

Own the convention question. Decide which names are allowed to live in more than one store at all, since a chain that silently resolves is only safe when the team agrees where each kind of value belongs.

## What `pm.variables` actually is In the Postman sandbox, `pm.variables` is **not a store of its own** the way `pm.environment`, `pm.collectionVariables` and `pm.globals` are. It is a `VariableScope` — the SDK's class for a named list of variables — that the sandbox has given **layers**. While building the `pm` object for one execution the sandbox calls `addLayer` four times, in exactly this order: 1. the iteration data list, 2. the environment's `values`, 3. the collection variables' `values`, 4. the globals' `values`. The scope's own `values` list holds the **local variables** — the entries a write through `pm.variables.set` lands in. That construction *is* the precedence rule. There is no priority field on a variable, no setting that reorders the stores, and nothing consulted at read time except the layer array in the order it was pushed. ## The walk `get` performs `VariableScope.get(key)` resolves a name in these steps: 1. Look the key up in the scope's **own `values`**. If an entry is there and is not disabled, return its value and stop — no layer is touched. 2. Otherwise iterate `_layers` from the front: **iteration data**. 3. Then the **environment**. 4. Then **collection variables**. 5. Then **globals**. 6. Stop at the first entry that exists and is not `disabled`, and return that entry's value. 7. If the loop ends without such an entry, return `undefined`. `has(key)` performs the identical walk and reports a boolean rather than a value, so the two always agree about which entry is in force. ## Which store wins | Name defined in | Also defined in | `pm.variables.get` returns | |---|---|---| | local values (`pm.variables.set`) | any store | the local value | | iteration data | environment | the iteration data value | | environment | collection variables | the environment value | | collection variables | globals | the collection variable value | | globals only | — | the global value | | nowhere | — | `undefined` | The sentence worth memorising: **the nearest layer wins, and globals are the last resort.** ## Addressing one store bypasses the walk entirely `pm.environment.get`, `pm.collectionVariables.get` and `pm.globals.get` each address a single scope. Those scopes are built without layers, so their `get` looks in their own `values` and stops there. This is the distinction candidates most often miss: - `pm.variables.get('host')` answers **"what is in force right now"** across the whole chain. - `pm.environment.get('host')` answers **"what does this one store say"**, and returns `undefined` when only a global defines the name — even though `pm.variables.get` would have found it. So the two calls legitimately disagree, and neither is broken when they do. ## Attribution — three different owners The pieces belong to three layers of the toolchain, and mixing them up is a common way to state this fact wrongly: - `VariableScope`, `addLayer` and the `_layers` array are the **SDK's**. - `pm.variables`, `pm.environment`, `pm.collectionVariables` and `pm.globals` are the **sandbox's** surface. - The `disabled` flag on a stored entry is a **collection-format** field the SDK honours during the walk. ## Consequences you can be asked about - **A global that "does nothing"** is almost always shadowed: some nearer layer — often the environment — carries the same name, and the walk stops before it reaches globals. - **Deleting the shadow reveals the layer beneath**, rather than leaving the name unresolved. Precedence is a chain, not an override slot. - **A missing name is not an error.** `get` returns `undefined` quietly; nothing throws and no default store is consulted. - **A disabled entry does not count as a match.** The walk steps over it and a farther store may answer instead. - **A local write shadows everything.** Because the scope's own `values` are checked before any layer, a value set through `pm.variables.set` outranks every store for subsequent reads through `pm.variables`. - **Order is not configurable.** The four `addLayer` calls are fixed by the sandbox; there is no knob that promotes globals above the environment. ## The shape of a good answer Name the chain in order, say that the first non-disabled match ends the search, and add why: `pm.variables` is a scope with layered lists, not an aggregating store with a precedence table. Then draw the practical conclusion — an environment entry beats a collection variable of the same name, and a global is only ever the fallback.

  • Where does a value written with pm.variables.set sit in that walk?
    In the scope's own `values` list, which `get` checks before any layer. It therefore shadows iteration data, the environment, collection variables and globals for reads through `pm.variables`. Nothing about the layers changes — the local entry is simply found first, so the layered stores still hold whatever they held.
  • If no store defines the name at all, what does pm.variables.get return?
    `undefined`. The walk falls off the end of the layer list and yields nothing: there is no exception, no default value and no further store consulted. `pm.variables.has` runs the same walk and reports `false` in exactly that situation, so the two never disagree.
  • Why can pm.environment.get and pm.variables.get return different things for one name?
    They ask different questions. `pm.environment` is a scope with no layers, so its `get` looks only at the environment's own entries. `pm.variables` carries the environment as one layer among four, so it can answer from iteration data, the collection or globals when the environment is silent — or from a local value that shadows all of them.

It reads like nested scopes in a program: the innermost binding actually in force answers, and the outermost one is consulted only when nothing nearer defines the name.

saying these in an interview costs you the question

  • Says globals override the environment rather than losing to it
  • Thinks a priority number stored on the variable decides the winner
  • Believes the last matching store wins instead of the first
  • Assumes an unresolved name throws instead of yielding undefined
  • Claims collection variables outrank environment values
  • Treats pm.variables and pm.environment as interchangeable readers
open as a page

In Postman variable resolution, how does a disabled entry affect which store's value a script reads?

level: middleimportance: must knowfreq 46%

basics

~20 s

A disabled entry counts as absent. Postman's VariableScope requires a match to be present and not disabled, so the search steps over it and continues into the next layer, letting a farther store supply the value.

open as a page

When one Postman variable store holds two entries with the same key, which one does a script read?

level: seniorimportance: should knowfreq 30%

basics

~20 s

The last enabled entry wins. Postman's SDK resolves a duplicated key by scanning the stored list in reverse for the first entry that is not disabled, so later definitions shadow earlier ones within the same store.

open as a page

In the Postman SDK, what does VariableScope.set do when the existing entry for that key is disabled?

level: seniorimportance: nice to knowfreq 24%

basics

~20 s

It appends a second entry rather than editing the existing one. Postman's SDK updates in place only when the entry it finds is enabled, so a disabled entry is left untouched and a new enabled entry joins it.

open as a page