Pass Node.js environment variable with Windows PowerShell

Set environmental variable MY_VAR first and run your app like this:

C:\Users\everton\my-project> $env:MY_VAR="8000" ; node index.js

You can access environmental variable MY_VAR inside index.js by

process.env.MY_VAR

Note: PowerShell doesn't directly support command-scoped environment variables. The above command sets the environment variable for that PowerShell session.


My answer require the use of Node.js and npm libraries.

...or you just take out the pain of writing obscure-WTF-language-scripting, and use one of command-scoped (plus cross-platform) Node.js scripts:

  • cross-env (for inline)

    cross-env MYVAR=MYVALUE node index.js
    
  • env-cmd (from .env file)

    env-cmd .env node index.js
    

    with

    #.env file
    MYVAR=MYVALUE
    

Note: If you can assume that Node.js is already installed - as is by definition the case when you're invoking node - consider use of npm helper packages, as shown in Cyril CHAPON 's helpful answer.
This answer focuses on generic solutions from within PowerShell.

tl;dr

# Set env. variable temporarily, invoke the external utility, 
# then remove / restore old value.
$oldVal, $env:MYVAR = $env:MYVAR, 8000; node index.js; $env:MYVAR = $oldVal
# Scoped alternative that uses a *transient* helper variable.
& { $oldVal, $env:MY_VAR = $env:MY_VAR, 8000; node index.js; $env:MY_VAR = $oldVal }

More simply, if there's no preexisting MY_VAR value that must be restored.

$env:MYVAR=8000; node index.js; $env:MYVAR=$null

See below for an explanation and an alternative based on a helper function.


To complement Harikrishnan's effective answer:

PowerShell has no equivalent to the command-scoped method of passing environment variables that POSIX-like shells offer (as of PowerShell v7 - however, introducing it to PowerShell - not necessarily with the same syntax - is being discussed in GitHub issue #3316); e.g.:

 # E.g., in *Bash*: 
 # Define environment variable MY_VAR for the child process being invoked (`node`)
 # ONLY; in other words: MY_VAR is scoped to the command being invoked
 # (subsequent commands do not see it).
 MY_VAR=8000 node index.js

In PowerShell, as Harikrishnan's answer demonstrates, you have to define the environment variable first, and then, in a separate statement, call the external program, so $env:MY_VAR="8000"; node index.js is the right PowerShell solution, but it is worth nothing that $env:MY_VAR stays in scope for the remainder of the session (it is set at the process level).

Note that even using a script block invoked with & to create a child scope doesn't help here, because such child scopes only apply to PowerShell variables, not environment variables.

You can, of course, remove the environment variable manually after the node call:
Remove-Item env:MY_VAR or even just $env:MY_VAR = $null, which is what the 1st command at the top shows.


A more structured alternative - perhaps better in the case of setting multiple environment variables and/or invoking multiple commands - is to use a script block invoked with &:

& { $oldVal, $env:MY_VAR = $env:MY_VAR, 8000; node index.js; $env:MY_VAR = $oldVal }

This takes advantage of:

  • { ... } is a script block that provides a clearly visible grouping for the commands in it; invoked with &, it creates a local scope, so that helper variable $oldVal automatically goes out of scope on exiting the block.

  • $oldVal, $env:MY_VAR = $env:MY_VAR, 8000 saves the old value (if any) of $env:MY_VAR in $oldVal while changing the value to 8000; this technique of assigning to multiple variables at once (known as destructuring assignment in some languages) is explained in Get-Help about_Assignment_Operators, section "ASSIGNING MULTIPLE VARIALBES".

Alternatively, use the helper function below, or use a try { ... } finally { ... } approach, as demonstrated in this related answer.


Helper function for command-scoped environment modifications.

If you define the helper function below (remember that function definitions must be placed before they're invoked), you can achieve command-scoped modification of your environment as follows:

# Invoke `node index.js` with a *temporarily* set MY_VAR environment variable.
Invoke-WithEnvironment @{ MY_VAR = 8000 } { node index.js }

Invoke-WithEnvironment() source code:

function Invoke-WithEnvironment {
<#
.SYNOPSIS
Invokes commands with a temporarily modified environment.

.DESCRIPTION
Modifies environment variables temporarily based on a hashtable of values,
invokes the specified script block, then restores the previous environment.

.PARAMETER Environment
A hashtable that defines the temporary environment-variable values.
Assign $null to (temporarily) remove an environment variable that is
currently set.

.PARAMETER ScriptBlock
The command(s) to execute with the temporarily modified environment.

.EXAMPLE
> Invoke-WithEnvironment @{ PORT=8080 } { node index.js }

Runs node with environment variable PORT temporarily set to 8080, with its
previous value, if any 
#>
  param(
    [Parameter(Mandatory)] [System.Collections.IDictionary] $Environment,
    [Parameter(Mandatory)] [scriptblock] $ScriptBlock
  )
  # Modify the environment based on the hashtable and save the original 
  # one for later restoration.
  $htOrgEnv = @{}
  foreach ($kv in $Environment.GetEnumerator()) {
    $htOrgEnv[$kv.Key] = (Get-Item -EA SilentlyContinue "env:$($kv.Key)").Value
    Set-Item "env:$($kv.Key)" $kv.Value
  }
  # Invoke the script block
  try {
    & $ScriptBlock
  } finally {
    # Restore the original environment.
    foreach ($kv in $Environment.GetEnumerator()) {
      # Note: setting an environment var. to $null or '' *removes* it.
      Set-Item "env:$($kv.Key)" $htOrgEnv[$kv.Key]
    }
  }
}