Skip to content

Run Node.js as a Windows service without PATH surprises

Verified 1 min read

Wrap Node with NSSM or WinSW, pin the absolute node.exe, set cwd/env, capture logs and verify the service uses the intended version.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Task

Node has no built-in Windows service mode. Use a wrapper:

  • NSSM — quick, interactive nssm install;
  • WinSW — XML config, good for repeatable deployments.

The service must run the absolute node.exe, not node from PATH.

Terminal window
nssm install api-a "C:\node\20\node.exe" "C:\apps\api-a\server.js"
nssm set api-a AppDirectory "C:\apps\api-a"
nssm set api-a AppEnvironmentExtra NODE_ENV=production PORT=3000
nssm set api-a AppStdout "C:\logs\api-a\out.log"
nssm set api-a AppStderr "C:\logs\api-a\err.log"
nssm set api-a AppRotateFiles 1
nssm start api-a

Set AppDirectory; Node resolves require('./...'), .env and relative paths from the working directory.

<service>
<id>api-a</id>
<name>API A</name>
<executable>C:\node\20\node.exe</executable>
<arguments>C:\apps\api-a\server.js</arguments>
<workingdirectory>C:\apps\api-a</workingdirectory>
<env name="NODE_ENV" value="production"/>
<env name="PORT" value="3000"/>
<logpath>C:\logs\api-a</logpath>
<log mode="roll-by-size"/>
<onfailure action="restart" delay="10 sec"/>
</service>

Install with winsw install / winsw start. Keep the XML next to the wrapper and version it.

  • Use a dedicated service account, not LocalSystem.
  • Grant read/execute on C:\node\20 and C:\apps\api-a.
  • Grant write only on the app’s logs/uploads/temp.
  • Do not give the app write access to C:\node.
Terminal window
sc.exe qc api-a
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
Select-Object ProcessId, ExecutablePath, CommandLine
Invoke-WebRequest http://localhost:3000/ -UseBasicParsing | Select-Object StatusCode
Get-Content C:\logs\api-a\err.log -Tail 50

ExecutablePath must be the pinned C:\node\20\node.exe. If it is the nvm symlink, an nvm use can change the service on next restart.

  1. Install the new Node beside the old.
  2. Test with the absolute path.
  3. Change the wrapper’s executable.
  4. Restart one service; verify ExecutablePath and logs.
  5. Keep the old version for rollback.

E1. Node/nvm and a service wrapper were not installed in this lab; the commands are the service pattern to verify on Server 2025.

Sources