Register Node.js apps as native Windows services. No NSSM. No VBScript. No
npm startrunning forever in a forgotten terminal.
node-winsvc turns any Node.js application into a first-class Windows service using the native Win32 Service Control Manager API — the same mechanism SQL Server, IIS and the Windows kernel use. The heavy lifting is done by a small Rust binary; you drive it with a friendly CLI.
npm install --save-dev node-winsvc
# or use it on demand, no install:
npx node-winsvc <command>npx node-winsvc init # create winsvc.config.json
npx node-winsvc install # register as a Windows service (Administrator)
npx node-winsvc start # start it (Administrator)
npx node-winsvc status # check it (Administrator)
npx node-winsvc logs -f # tail the service log
npx node-winsvc restart # stop + start (Administrator)
npx node-winsvc stop
npx node-winsvc uninstallA minimal winsvc.config.json:
{
"name": "my-api",
"displayName": "My Node API",
"description": "Production Node.js API service",
"script": "dist/server.js",
"nodeArgs": [],
"env": { "NODE_ENV": "production", "PORT": "8080" },
"autoRestart": true,
"startType": "auto",
"logFile": "logs/service.log",
"workingDirectory": "."
}That's it — your app now starts on boot, survives logoff, restarts on crash, and shows up in services.msc.
The usual ways to keep a Node app alive on Windows are all compromises:
| Approach | Problem |
|---|---|
npm start in a terminal |
Dies when the session closes. Not a real service. |
pm2 |
Cross-platform, but not a native Windows service; needs pm2 itself running. |
NSSM |
External .exe you must ship and trust; abandoned-ish. |
node-windows |
Generates VBScript wrappers; fragile, hard to debug. |
node-winsvc registers the service directly with CreateServiceW. Windows itself supervises the process, restarts it on boot, and shows it in services.msc.
┌─────────────────────────────┐
│ CLI (TypeScript, strict) │ npx node-winsvc <command>
│ src/cli/*.command.ts │
└──────────────┬──────────────┘
│ spawnSync (args)
▼
┌─────────────────────────────┐
│ Core (Rust + Win32) │ node-winsvc-core.exe
│ rust/src/commands/*.rs │ CreateServiceW / StartServiceW / ...
└──────────────┬──────────────┘
│ Win32 SCM API
▼
Windows Service Control Manager
- TypeScript layer — reads
winsvc.config.json, validates, locates the bundled binary, and calls it. Clean Code: models / services / cli / utils separated, one responsibility per file. - Rust core —
node-winsvc-core.exe, a tiny clap CLI that talks to the Win32 Service Control Manager. Shipped inside the npm package (bin/node-winsvc-core.exe).
npm install --save-dev node-winsvc
# or run on demand:
npx node-winsvc <command>Windows only. Requires Administrator privileges for
install/uninstall/start/stop(the Service Control Manager demands it).
npx node-winsvc init creates this template:
{
"name": "my-api",
"displayName": "My Node API",
"description": "Production Node.js API service",
"script": "dist/server.js",
"nodeArgs": [],
"env": { "NODE_ENV": "production", "PORT": "8080" },
"autoRestart": true,
"startType": "auto",
"logFile": "logs/service.log",
"workingDirectory": "."
}| Field | Meaning |
|---|---|
name |
Internal Windows service name (no spaces). |
displayName |
Name shown in services.msc. |
description |
Description shown in the Services panel. |
script |
Entry .js relative to the project. |
nodeArgs |
Extra args passed to node.exe. |
env |
Environment variables injected into the process. |
autoRestart |
Restart the process if it crashes. |
startType |
auto | manual | disabled. |
logFile |
stdout/stderr log file (relative to project). |
workingDirectory |
Working directory (default: project root). |
| Command | What it does | Admin |
|---|---|---|
init |
Create winsvc.config.json. |
no |
install |
Register the service (CreateServiceW). |
yes |
uninstall |
Remove the service (DeleteService). |
yes |
start |
Start the service (StartServiceW). |
yes |
stop |
Stop the service (ControlService STOP). |
yes |
restart |
Stop then start the service. | yes |
status |
Query state (QueryServiceStatus) → JSON. |
yes |
logs |
Print the service log (-f follow, -n <N> lines). |
no |
# 1. Build the Rust core
npm run build:rust # cargo build --release
npm run bundle:exe # copies the exe into bin/
# 2. Build the TypeScript CLI
npm run build # tsc → dist/- Service-runner mode: the Rust core acts as the service host (
StartServiceCtrlDispatcherW+ child-process supervision + auto-restart). - Live log tail:
node-winsvc logs -f. -
node-winsvc restart. -
npx node-winsvc doctor— diagnose permissions / Node path / config. - Real PID + uptime in
status. - Health-check hooks.
MIT © Henry Moreno