setx and $env: Set Environment Variables in CI
setx writes a persistent environment variable to the registry (User or, with /M, Machine), while $env: and cmd set affect only the current process, so the two are not interchangeable.
The classic Windows CI trap: setx persists a variable but does not update the running shell, so the very next command in the same step cannot see it. Knowing which mechanism to use avoids hours of confusion.
What it does
setx writes a variable to the User (default) or Machine (/M) environment in the registry; it takes effect in *future* processes, not the current one. $env:NAME in PowerShell and set NAME=value in cmd set a variable for the current process and its children only.
Common usage
:: persist for future steps/sessions (machine-wide needs admin)
setx MY_TOOL_HOME "C:\tools\mytool" /M
:: set for the CURRENT process (PowerShell)
$env:PATH = "C:\tools\mytool\bin;$env:PATH"
:: GitHub Actions: persist to later steps via the env file
"MY_VAR=value" | Out-File -Append -Encoding utf8 $env:GITHUB_ENVOptions
| Construct | What it does |
|---|---|
| setx NAME value | Persist a User variable (future processes) |
| setx NAME value /M | Persist a Machine variable (needs admin) |
| $env:NAME = "v" | PowerShell: set for the current process |
| set NAME=value (cmd) | cmd: set for the current process |
| $env:GITHUB_ENV / GITHUB_PATH | GitHub Actions files to pass vars/PATH to later steps |
In CI
To pass a value to *later* steps on GitHub Actions, append to $env:GITHUB_ENV (or GITHUB_PATH for PATH), not setx, which the runner does not reload mid-job. To use a value *within* the same step, set $env:NAME directly. Use setx only for state that must survive into a different process you launch.
Common errors in CI
The most common bug: setx FOO bar then echo %FOO% in the same step prints nothing, because setx does not change the current process; set %FOO%/$env:FOO directly for immediate use. "ERROR: Access to the registry path is denied." means /M without elevation. "WARNING: The data being saved is truncated to 1024 characters" means the value (often a long PATH) exceeds setx's 1024-char limit; edit PATH another way.