Open-source project
winsw/winsw avatar
winsw/winsw

WinSW: running any executable as a Windows service with an XML file

A wrapper executable that can run any executable as a Windows service, in a permissive license.

14,331 stars1,702 forksC#MIT

At a glance

What is it?
WinSW wraps a normal program in a Windows service using a small XML config and a renamed executable. It is a good fit when you need SCM integration without writing service code, and a poor fit when you need a Linux or macOS service manager.
Who is it for?
WinSW suits teams that must register a long-running process with the Windows Service Control Manager and want the service definition kept in a text file they can review and version. It is the wrong tool for Linux or macOS hosts, for short-lived batch jobs, and for anyone who needs a stable 3.x release today, since the newest published 3.x build is v3.0.0-alpha.11 from 2023-01-29 and the stable line is 2.12.0.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 62 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap WinSW fills between a program and the Windows Service Control Manager

A normal console program, a Java jar, a Python script or a Node process cannot be registered with the Windows Service Control Manager on its own. The SCM expects an executable that speaks the service control protocol: it must report status, respond to stop requests, and survive the session ending. WinSW is a wrapper executable that sits in that position and starts your program as a child process.

The audience is narrow but real. It is for someone who has a working command line, usually one that already runs in production under a console window or a scheduled task, and now needs it to start at boot, appear in services.msc, and be stoppable through the standard tooling. The README frames the project as "a wrapper executable that can run any executable as a Windows service, in a permissive license," and the licence point matters to some adopters: MIT, with the licence file at LICENSE.txt in the repository root.

The alternative most people reach for is writing a small service host themselves, or using a tool that installs a service by generating a wrapper for you. WinSW's bet is that the service definition belongs in a file you can read, diff and keep next to the application it launches, rather than in code or in an installer.

How the wrapper, the XML file and the service name fit together

The mechanism is discovery by filename. In the bundled-tool form, you take WinSW.exe or WinSW.zip from the distribution, rename the executable to whatever you like (the README uses myapp.exe), and place it beside an XML file with the matching name, myapp.xml. The README states this plainly: place those two files side by side, "because that's how WinSW discovers its co-related configuration." That single sentence explains most of the confusion new users hit, because a mismatched name produces a wrapper that cannot find its service definition.

The XML file is the service definition. The sample in the README, which it says is used in the Jenkins project, contains an id, a display name, a description, an environment variable, an executable, arguments and a log element:

xml
<service>
  <id>jenkins</id>
  <name>Jenkins</name>
  <description>This service runs Jenkins continuous integration system.</description>
  <env name="JENKINS_HOME" value="%BASE%"/>
  <executable>java</executable>
  <arguments>-Xrs -Xmx256m -jar "%BASE%\jenkins.war" --httpPort=8080</arguments>
  <log mode="roll"></log>
</service>

The id becomes the service name in the SCM, and %BASE% expands to the directory holding the wrapper, which is how the sample points at a jar next to the executable rather than at an absolute path. The full element list lives in docs/xml-config-file.md, and the repository ships samples/minimal.xml, samples/complete.xml, samples/jenkins.xml and samples/shared-directory-mapper.xml. The global-tool form skips the renaming: you run winsw install myapp.xml and pass the config path explicitly, which is the form to prefer when one wrapper manages several services.

Logging is configured, not assumed. The sample uses log mode roll, and the README links docs/logging-and-error-reporting.md for the rest. If you leave logging unspecified, do not expect the wrapper to invent a log location for you; that is a configuration decision, and it is the first thing to settle for a service that will run unattended for months.

Installing WinSW and registering a first service

Get the binaries from GitHub Releases, which the README names as the source for both stable 2.x releases and 3.x pre-releases. The project also points at Azure Pipelines for CI builds, at NuGet for 2.x, and at the Jenkins-hosted Maven packaging for 2.x executables. There is no installer; the download is an executable or a zip.

Once you have the wrapper beside its XML file, the install step is a single command run from an elevated prompt. The README notes that most commands require Administrator privileges and that WinSW will prompt for UAC in non-elevated sessions.

bash
myapp.exe install

After install, start the service and then check it:

bash
myapp.exe start
myapp.exe status

The status command is the one to trust first. If the service registers but exits immediately, the wrapper's own log, configured through the log element, is where the child process's output lands. The README's troubleshooting page is at docs/troubleshooting.md, and for a service that has stopped responding there are experimental commands: dev ps draws the process tree associated with the service, dev kill terminates it, and dev list lists services managed by the current executable. Treat those three as experimental, since that is how the project labels them.

The remaining commands in the documented set are uninstall, stop, restart, refresh and customize. refresh is the interesting one: it refreshes service properties without reinstalling, which means you can edit the XML and apply the change without tearing the service registration down.

Platform reach and the .NET runtime you must already have

WinSW 3 runs on Windows platforms with .NET Framework 4.6.1 or later. The README notes that .NET Framework has shipped with Windows since Windows 10 version 1511 and Windows Server 2016, and can be installed back to Windows 7 SP1 and Windows Server 2008 R2 SP1. For systems without .NET Framework, the project publishes native 64-bit and 32-bit executables built on .NET 7, supported since Windows 10 version 1607, Windows Server (Core) 2012 R2 and Nano Server version 1809.

That splits the download decision in two, and the split is not cosmetic. A machine with only .NET Framework needs the framework build; a stripped-down image without it needs the native build. The README says more executables can be added upon request, which is an honest way of saying the matrix is finite and community-driven rather than universal.

There is also a version-line trap. The README states that development of WinSW 3.x happens on the default branch v3, that GitHub Releases holds stable 2.x releases and 3.x pre-releases, and that NuGet and Maven packages currently correspond to 2.x. So a team that installs from NuGet gets 2.x, while a team that downloads a release asset may be pulling a 3.x pre-release. Both are legitimate paths, but they are different codebases, and the migration document at docs/migrate-to-3-x.md exists precisely because the configuration and behaviour changed between them.

Where WinSW is the wrong tool

The first limitation is the platform itself. WinSW is a Windows service wrapper. There is no Linux systemd unit, no macOS launchd plist, and no container-native story in the README. If your deployment target is a Linux host, this project is not a candidate, and no amount of configuration will change that.

The second is the release situation. The most recent release listed is v3.0.0-alpha.11 from 2023-01-29, alongside v2.12.0 from 2023-01-28. The repository's last push was on 2026-07-30, so work has continued on the default branch, but the published artefacts lag that work considerably. Anyone who needs a supported, stable 3.x binary today should plan on 2.12.0 or on building from the v3 branch, and should read docs/migrate-to-3-x.md before assuming a 3.x config is portable back to 2.x.

The third is scope. WinSW starts a process and supervises it. It is not a scheduler, not a log aggregator, and not a configuration management system. If your real requirement is "run this job every night at 02:00," a scheduled task is the direct answer and WinSW is an unnecessary layer. If your requirement is "keep this daemon alive and let me stop it from services.msc," then it is the right shape.

Finally, there is no rollback documentation in the README. The command table lists install, uninstall, start, stop, restart, status, refresh, customize and the experimental dev commands, and the README does not document a rollback path for a failed upgrade. Plan your own by keeping the previous wrapper and XML before you replace them.

WinSW versus NSSM: two different answers to the same question

NSSM is the comparison people search for, and the difference is in how the service is defined. NSSM installs a service through an interactive GUI: you run nssm install, a dialog collects the executable path, arguments, working directory and restart behaviour, and the settings are written into the Windows registry under the service's parameters key. There is no file you check into version control unless you export one yourself.

WinSW inverts that. The service definition is an XML document that lives beside the wrapper, which means the config can be reviewed in a pull request, generated by a deployment script, and copied between machines as a file. The wrapper executable is also renamed per service, so each service carries its own binary and its own XML rather than sharing one manager.

That comes at a cost. NSSM's GUI is friendlier for a one-off service on a developer's laptop, and its settings are editable without touching a file. WinSW expects you to know the element names before you start, and a typo in the XML produces a service that installs and then misbehaves rather than a dialog that validates your input. The trade is deliberate: file-based configuration is what makes WinSW usable in an automated deployment, and it is why the Jenkins project's sample config is the one shown in the README.

Editorial conclusion

WinSW suits teams that must register a long-running process with the Windows Service Control Manager and want the service definition kept in a text file they can review and version. It is the wrong tool for Linux or macOS hosts, for short-lived batch jobs, and for anyone who needs a stable 3.x release today, since the newest published 3.x build is v3.0.0-alpha.11 from 2023-01-29 and the stable line is 2.12.0. Before adopting it, verify three things on your own machine: that your target Windows version has .NET Framework 4.6.1 or later, or that you are using the native .NET 7 executable; that the executable and its XML sit side by side if you intend to use the bundled-tool form; and what your chosen log mode does to disk usage under a service that runs for months.

Frequently asked questions

What is WinSW?

WinSW is a wrapper executable that runs any executable as a Windows service, distributed under the MIT licence and written in C#. It is configured through an XML file that defines the service id, display name, executable, arguments and logging behaviour.

How to install WinSW?

Download WinSW.exe or WinSW.zip from GitHub Releases, then either rename the executable to match an XML file placed beside it and run myapp.exe install, or run winsw install myapp.xml as a global tool. Most commands need Administrator privileges, and WinSW prompts for UAC in non-elevated sessions.

What is a Windows service wrapper?

It is an executable that speaks the Windows Service Control Manager protocol on behalf of a program that cannot do so itself, starting that program as a child process and reporting its status. WinSW fills that role so a console application or script can appear in services.msc and start at boot.

What are the key differences between WinSW and NSSM?

WinSW defines the service in an XML file stored next to a renamed wrapper executable, so the definition can be version controlled and deployed as a file. NSSM configures the service through an interactive GUI and stores the settings in the Windows registry.

What is winsw x64 exe?

It refers to the native 64-bit executable the project publishes for systems without .NET Framework, built on .NET 7. The README states that .NET 7 builds are supported since Windows 10 version 1607, Windows Server (Core) 2012 R2 and Nano Server version 1809.

Is WinSW safe to use?

The project is licensed under MIT, and the README notes that most commands require Administrator privileges and that WinSW prompts for UAC in non-elevated sessions, so the wrapper runs with the rights you grant the service. The documentation does not make a security claim beyond that, so evaluate the binary source you download from.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. winsw/winsw on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/winsw-winsw.svg)](https://hysenlabs.com/projects/winsw-winsw)