service

A Go library that installs, starts, stops, and runs any program as a native system service on Windows, Linux, and macOS.

Library
Go
vv1.3.0
4,838stars
Zlib

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
62/100Good
Development Activity52
Maintenance8
Community88
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
66/100Good
Architecture78
Code Quality62
Innovation58
Learning Curve65

kardianos/service solves a problem every long-running Go program eventually hits: turning a plain binary into a proper, OS-managed background service. Rather than shelling out to platform-specific tooling or hand-rolling init scripts, it exposes a single Interface (Start/Stop) and Config struct that the library maps onto whatever service manager the host actually uses — Windows Service Control Manager, systemd, Upstart, SysV, OpenRC on Linux, or Launchd on macOS.

Under the hood each platform gets its own implementation (service_windows.go, service_systemd_linux.go, service_upstart_linux.go, service_openrc_linux.go, service_sysv_linux.go, service_darwin.go), all satisfying the same System/Service interfaces so calling code never branches on OS. The library also detects whether a binary is currently running interactively (from a terminal) or as a managed service, which is the piece most hand-rolled daemon code gets wrong or skips entirely.

It’s a foundational piece for any Go CLI or agent that needs to run unattended as install/start/stop/uninstall — log shippers, local agents, background workers, and dev tools that need to survive reboots without asking the operator to learn systemd unit files or Windows service registration by hand.

What You Get

  • A unified service.New(program, config) API that abstracts Windows Service Control Manager, systemd, Upstart, SysV, OpenRC, and Launchd behind one interface
  • Automatic detection of whether the current process is running interactively (terminal) or as a managed service, via Interactive()
  • Built-in service lifecycle actions — install, uninstall, start, stop, restart — driven from Service.Run() and Service.Control()
  • A pluggable Logger that routes to the platform’s native logging facility (Windows Event Log, syslog, os.Stdout) without extra wiring
  • Config options for run-as user, working directory, environment variables, dependencies, and platform-specific service manager options

Common Use Cases

  • Packaging a Go CLI or agent (log shipper, monitoring probe, sync daemon) so ops teams can install/start/stop it with normal OS service commands instead of a custom init script
  • Building cross-platform background workers that must auto-start on boot on Windows, Linux, and macOS from one codebase
  • Detecting at runtime whether a binary was launched by a human in a terminal versus by the OS service manager, to change logging or behavior accordingly
  • Wrapping an existing long-running Go process with install/uninstall commands for distribution as a self-installing service binary

Under The Hood

Architecture The library centers on two small interfaces defined in service.goInterface (the caller’s Start/Stop hooks) and Service/System (what a platform backend must implement) — with ChooseSystem letting each platform file register itself via init(). service_linux.go picks among systemd, Upstart, SysV, OpenRC, and RCS backends at runtime by probing for /proc/1/cgroup, mount info, and known init binaries, while service_windows.go and service_darwin.go implement the same contract against the Windows SCM and Launchd respectively. template.go renders each platform’s native unit/plist/init-script format from a shared Go template, so adding config options only touches one file per platform rather than a shared core. This keeps the public API stable while isolating nearly all OS-specific complexity behind the System interface — the design would break down only if a future platform couldn’t be expressed as install/start/stop/detect operations at all.

Tech Stack This is a low-dependency Go module (go 1.23, one external dependency: golang.org/x/sys) with no build tooling beyond the standard go build/go test toolchain. Platform-specific files use Go’s _linux.go/_windows.go/_darwin.go build-constraint naming so the compiler includes only the relevant backend per target OS. CI is configured through both Travis (Linux, multiple Go versions, ppc64le/amd64) and AppVeyor (Windows), reflecting the cross-platform nature of what’s being tested.

Code Quality Test coverage is present but uneven: service_test.go, service_linux_test.go, service_systemd_render_test.go, service_sysv_render_test.go, template_test.go, version_test.go, and name_test.go cover core logic and per-platform rendering, with a dedicated linux-test-su.sh script and su/nosu-tagged tests for permission-sensitive install/uninstall paths. Error handling favors explicit returned error values over panics throughout, and naming is consistent with idiomatic Go conventions. There’s no linter config or golangci-lint setup checked in, and the README itself documents known gaps (Dependencies field unimplemented on Linux/Launchd), which is an honest signal about maintenance depth rather than a red flag.

What Makes It Unique The distinguishing design choice is treating “is this process running interactively or as a service” as a first-class, cross-platform primitive (Interactive()) rather than something each consumer has to reimplement per OS — genuinely useful and not something most comparable daemon-wrapper libraries expose as cleanly. Beyond that it’s a solid, standard adapter-pattern implementation over well-known service managers rather than a novel approach to service management itself.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search