Hoppscotch Environments and {{ }} Variables: Resolution Order and Practical Setup
Hoppscotch replaces {{variables}} at send time using the active environment. Here is the resolution order, a worked setup, and the mistakes that produce stale values.
30 Jul 2025, 02:04 UTC

The useful answer
In Hoppscotch, {{name}} placeholders in a URL, header, query parameter or body are replaced with values from the environment you have selected, and the substitution happens on the client immediately before the request is sent. Nothing is evaluated on a server, and nothing is recalculated after the response arrives. If a request is using a stale value, the cause is almost always the active environment, a request-level variable shadowing the environment, or a name that does not match exactly.
What interpolation does at send time
An environment is a named set of key-value pairs. You select one environment as active; Hoppscotch scans the outgoing request for {{key}} patterns and substitutes the matching value as plain text. The placeholder can appear anywhere the request is assembled: the URL field, header values, query parameter values, and request bodies.
A worked configuration
Assume two environments, Staging and Local, each holding the same two keys:
Staging
baseUrl = https://api.example.com
token = staging-token-value
Local
baseUrl = http://localhost:8080
token = local-token-value
With Staging active, build a GET request:
- URL:
{{baseUrl}}/users - Header
Authorization:Bearer {{token}}
On send, the outgoing request becomes GET https://api.example.com/users with Authorization: Bearer staging-token-value. Switch the active environment to Local and resend: the same request definition now targets http://localhost:8080/users with the local token. The request itself never changed — only the selected environment did. That is the point of the feature: one request definition, many targets.
Resolution order
When the same key exists in more than one scope, the narrowest scope wins.
| Scope | Behaviour |
|---|---|
| Request-level variables | Highest precedence; override anything defined in the environment. |
| Active environment | Used for keys not defined at request level; overrides global defaults. |
| Global defaults | Fallback for keys absent from the active environment. |
Two consequences follow. First, defining a key at request level means changing the environment will not change that value — a frequent source of confusion when a value refuses to move off staging. Second, if a key exists only in one environment, switching environments leaves the placeholder unresolved rather than falling back to another environment's value.
Limits of the substitution model
- Flat text only. There are no expressions, concatenation or functions. A placeholder is replaced by one value; to build a path, place literal text next to it, as in
{{baseUrl}}/users. - No nested resolution in one pass. If a variable's value itself contains another placeholder, do not expect a second round of substitution.
- No automatic capture from responses. A token returned by a login call is not stored for you. Capturing it requires explicitly setting the variable from a test or script, and that behaviour is worth confirming in your build.
- Secrets are plain text. Environment values live in browser or desktop local storage and are visible in the UI. There is no encryption layer. Treat anything you put there as readable by anyone with access to that profile.
- Build differences. The web app, desktop app and self-hosted deployments can differ in where environment controls sit and which features are present, and this can change between releases.
Common mistakes
- Wrong active environment. The most common cause of a request hitting the wrong host. Check the environment selector before debugging anything else.
- Typos and case. Names are matched literally, so
{{token}}and{{Token}}are different keys. An unmatched placeholder is left as-is or resolves to nothing, producing a malformed URL or header rather than an obvious failure. - Request-level shadowing. A leftover request-level variable silently overrides the environment value you just edited.
- Same key, different environments. Reusing
baseUrlacross environments is good practice, but only if you remember to switch the active one. Otherwise you get a stale target with no error. - Assuming server-side evaluation. Because substitution is client-side, anything that needs logic — signing, hashing, timestamps — must be produced before the request is assembled.
How to verify a setup
- Create two environments with the same keys and clearly different values.
- Build one request using
{{baseUrl}}and{{token}}. - Send with the first environment active and inspect the resolved request — the URL and headers as actually sent.
- Switch environments and resend. The resolved values should change; the request definition should not.
- Open the request history entry for each send and compare the resolved URL and header, not just the status code.
If the resolved values do not change when you switch environments, look for a request-level variable with the same name, then check the spelling and case of the placeholder. If a value looks correct in the environment editor but wrong on the wire, you are almost certainly looking at a different environment than the one you edited.
A note on scope: this describes the general behaviour of environment-based interpolation. Exact UI placement and the availability of scripting hooks vary by build and release, so confirm against the version you are running before relying on it in a shared workflow.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.