Open-source project
microsoft/go-winio avatar
microsoft/go-winio

go-winio gives Go programs named pipes and Windows file handles without blocking OS threads

Win32 IO-related utilities for Go

1,085 stars218 forksGoMIT

At a glance

What is it?
go-winio is a Microsoft-maintained Go library for Win32 IO operations, focused on named pipes, other file handles and using pipes as a network transport, built on IO completion ports so goroutines are not pinned to threads. It fits a Go service on Windows that has to talk to Windows-specific IPC, and it does not fit a cross-platform service, since the library is Windows-only.
Who is it for?
go-winio fits a Go team on Windows that needs to speak to a Windows-only IPC mechanism, such as a Docker or container runtime using named pipes, and it does not fit a service that has to run on Linux or macOS as well, because the library is Windows-specific. Before adopting it, confirm your target is Windows Vista or newer, since the completion port design limits support to that era, and note that the module currently requires Go 1.26.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 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

The scope is narrow: named pipes, file handles and pipes as a transport

go-winio contains utilities for efficiently performing Win32 IO operations in Go. The README is precise about the current focus: accessing named pipes and other file handles, and using named pipes as a net transport.

That is a deliberately small surface. It is not a general Win32 binding, and it is not a syscall wrapper for the whole Windows API. It is the part of Win32 that Go's standard library does not cover and that a Go program needs in order to interop with another Windows program over a pipe.

The named pipe is the primitive that makes it useful. Windows programs, particularly container tooling and build systems, expose their control interfaces as named pipes rather than over a socket or a TCP port, and the pipe path is a filesystem-like name. A Go program that needs to drive such a program needs to open that pipe, write to it and read from it, and the standard library has no way to do that.

Using named pipes as a net transport is the second use case, and it is the one that makes this a networking library rather than a file library. A pipe can be handed to the standard net package machinery, so a Go program can accept a connection over a pipe in the same way it accepts a TCP connection, and remote clients can be given a pipe path as their address.

The project is MIT licensed, the last push was on 2026-10-14, and the release history shows v0.6.4 on 2026-10-13 and v0.6.3 on 2026-10-08 after v0.5.3 in May 2024.

IO completion ports are why the library exists at all

The mechanism that makes the library work is stated in one sentence and it explains the whole design. This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go to reuse the thread to schedule another goroutine.

The problem this solves is specific to Go on Windows. A blocking read on a Windows file handle parks the OS thread, not the goroutine, because a plain synchronous read keeps the calling thread occupied until it returns. The practical effect in a Go program is that a few hundred concurrent pipe connections will exhaust the thread pool, because each blocked read is holding a thread that the runtime cannot use for anything else.

By issuing the operation asynchronously and having the completion port deliver the result, the goroutine blocks in the runtime's own scheduler instead of in the kernel, and the OS thread returns to the pool immediately. The README draws the parallel with Go's own net package explicitly, saying this is similar to the implementation of network sockets in Go's net package, which is the point, because that implementation solved the same problem for sockets.

The cost of the design is stated too. This limits support to Windows Vista and newer operating systems. Completion ports are old technology, so the floor is a low one, but the floor is real and the library will not run on anything older.

The repository covers far more than pipes

The top level of the repository is a good catalogue of what the library actually does, and it is much wider than the README's summary suggests.

The pipe and file layers are the core: pipe.go and pipe_test.go for named pipes, file.go and file_test.go for file handles, and fileinfo.go with its own test file for file metadata. syscall.go and zsyscall_windows.go hold the syscall layer, and ea.go with ea_test.go covers extended attributes, with reparse.go and reparse_lx_test.go handling reparse points.

Then there is a set of modules that are Windows features rather than IO primitives. sd.go and sd_test.go handle security descriptors. privilege.go and privileges_test.go deal with token privileges, which is what a server needs to impersonate a client or to enable a privileged operation. hvsock.go and its test files implement Hyper-V sockets, and hvsock_fuzz_test.go shows that path is fuzzed.

Two directories are separate features with their own model. The vhd/ directory handles virtual hard disk files, and wim/ handles Windows Imaging Format files, which is the container format Windows uses for its own system images. The backuptar/ directory and backup.go with backup_test.go cover the tar-based backup format, and the pkg/ and internal/ directories hold the public and internal package layout. tools/ holds the tool directory.

The result is a library that reaches well past the summary line, which is worth knowing before you adopt it, because the pieces you did not expect are the ones that determine the size of the dependency.

Dependencies are two, and one of them is a logging library

The go.mod is short and worth reading before you add it to a dependency-sensitive project.

The module is github.com/Microsoft/go-winio and it requires Go 1.26.0. The direct dependencies are github.com/sirupsen/logrus at v1.10.2 and golang.org/x/sys at v0.49.0, with golang.org/x/mod, golang.org/x/sync and golang.org/x/tools as indirect requirements, and a tool directive on golang.org/x/tools/cmd/stringer.

golang.org/x/sys is the expected one, since the library is fundamentally a set of Windows syscalls. The logrus dependency is the more interesting choice for a library. Logrus is a structured logging library, and having it in the dependency list of a low-level IO package means the package either logs or exposes logging hooks, and either way a Go service that does not already use logrus acquires it. That is a small but real consideration when a package is meant to be embedded in something else.

The stringer tool directive points at the code generation approach. The README explains that the pipeline checks that auto-generated code, via go generate, are up to date, and that this can be done for the entire repo with go generate ./... . The generated files are checked in, and the CI verifies they match what the generator would produce, which is the pattern that keeps generated syscall wrappers from drifting.

Contributing means a CLA, a sign-off and a lint pass

The contribution requirements are documented in more detail than most libraries bother with, and they describe the Microsoft open source process rather than anything specific to this code.

Most contributions require agreeing to a Contributor License Agreement, the Microsoft CLA, declaring that you have the right to, and actually do, grant the rights to use your contribution. A CLA-bot checks the pull request and decorates it, and the README notes you will only need to do this once across all repos using that CLA.

On top of that, the pull request pipeline requires code sign-off. Contributors must sign their commits using git commit --signoff to certify that they either authored the work themselves or otherwise have permission to use it. A range of commits can be signed with git rebase --signoff. The CI uses the DCO GitHub app to ensure all commits in a given pull request are signed off.

Linting is the third step. Code must pass a linting stage using golangci-lint, with the settings in .golangci.yaml, and the README shows both the VSCode integration, through the go.lintTool and go.lintOnSave workspace settings, and the local invocation:

shell
# use . or specify a path to only lint a package
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
> golangci-lint run ./...

The project also adopts the Microsoft Open Source Code of Conduct. The README credits natefinch for the inspiration for the library and points at npipe as another named pipe implementation.

Where go-winio is the wrong tool

The first wrong-tool case is a cross-platform service. Every file in this repository is Windows-specific, and the mechanism is a Windows-specific one. A Go service that has to run on Linux and Windows needs an abstraction layer above the pipe, and on the non-Windows side that layer has to be something else entirely. If your deployment is Linux, this library does not apply, and the closest equivalent in the Go ecosystem is a Unix domain socket, which the standard library supports.

The second is a service that already solved the problem. Named pipes are one transport among several. A local TCP or Unix socket serves the same purpose for many tools, and if the Windows program you need to talk to offers a socket, using it avoids a dependency on a Windows-only package entirely. The library earns its place when the pipe is the only option the other end offers, which is exactly the container and tooling case.

The third is the dependency cost in a minimal image. Logrus and golang.org/x/sys come with it, and the library covers a wide area including VHD and WIM handling, so a project that only needs pipe transport is pulling in a package whose other features it will never use. The Go module system handles unused packages inside a module fine, since it compiles per package, but the module graph and the licence review still cover the whole thing.

The fourth is the maintenance window. The releases jumped from v0.5.3 in May 2024 to v0.6.3 in October 2026, which tells you the project was quiet for a long stretch and then moved through a major version quickly. The last push is recent, on 2026-10-14, and the current release is v0.6.4 from 2026-10-13, so the activity is real, but the gap in the middle is a reminder that this is a Windows-flavoured utility maintained alongside the wider Go Windows ecosystem rather than a project with a steady public cadence.

Editorial conclusion

go-winio fits a Go team on Windows that needs to speak to a Windows-only IPC mechanism, such as a Docker or container runtime using named pipes, and it does not fit a service that has to run on Linux or macOS as well, because the library is Windows-specific. Before adopting it, confirm your target is Windows Vista or newer, since the completion port design limits support to that era, and note that the module currently requires Go 1.26.0.

Frequently asked questions

What does go-winio do?

It provides utilities for efficiently performing Win32 IO operations in Go, currently focused on accessing named pipes and other file handles, and on using named pipes as a net transport. It relies on IO completion ports to avoid blocking IO on system threads so Go can reuse the thread to schedule another goroutine.

Which Windows versions does go-winio support?

The README states that the IO completion port design limits support to Windows Vista and newer operating systems. The library is therefore Windows-specific, and the go.mod requires Go 1.26.0.

What does the go-winio module depend on?

Two direct dependencies, github.com/sirupsen/logrus at v1.10.2 and golang.org/x/sys at v0.49.0, plus golang.org/x/mod, golang.org/x/sync and golang.org/x/tools as indirect requirements. A tool directive on golang.org/x/tools/cmd/stringer covers the generated code.

How do I contribute to go-winio?

Contributions require agreeing to the Microsoft CLA, signing commits with git commit --signoff so the DCO app can verify them, and passing the golangci-lint stage with the settings in .golangci.yaml. The CI also checks that go generate ./... output is up to date.

Official sources

  1. Issues
  2. License: MIT
  3. microsoft/go-winio on GitHub
  4. README
  5. Releases
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/microsoft-go-winio.svg)](https://hysenlabs.com/projects/microsoft-go-winio)

Was this useful?