# hcsshim: the Go interface to Windows containers and the runhcs shim

> hcsshim is the Go library that talks to the Windows Host Compute Service, and it is the layer under Docker and containerd on Windows rather than a container runtime of its own. The interesting change in the current tree is the split of the monolithic runhcs V1 shim into per-platform V2 shims, one per isolation model, with the LCOW one shipped and the WCOW and process variants still marked as coming soon.

**microsoft/hcsshim** — Windows - Host Compute Service Shim

- Repository: https://github.com/microsoft/hcsshim
- Stars: 699 · Forks: 306
- Language: Go
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/microsoft-hcsshim

## What hcsshim actually is, and who calls it

hcsshim stands for the Windows Host Compute Service Shim, and the README is precise about its role. This package contains the Golang interface for using the Windows Host Compute Service to launch and manage Windows Containers. It also contains other helpers and functions for managing Windows Containers, such as the Golang interface for the Host Network Service, as well as code for the guest agent, commonly referred to in the codebase as the GCS or Guest Compute Service, used to support running Linux Hyper-V containers.

Three interfaces in one repository, then. HCS is the compute side, the thing that starts a container or a utility VM. HNS is the network side, with a file per concern: hnsendpoint.go, hnsnetwork.go, hnspolicy.go, hnspolicylist.go, hnsglobals.go, hnsaccelnet.go and hnssupport.go, plus an hcn/ directory. The guest agent is the piece that runs inside the Linux utility VM and talks back to the host.

Who uses it is stated plainly: it is primarily used in the Moby and Containerd projects, but it can be freely used by other projects as well. That phrasing matters for anyone reading it as a general purpose library, because the two big consumers have driven its API shape toward exactly what a container runtime needs, not toward a general container management surface.

The code is Go, MIT licensed, the last push was on 2026-10-19, and the newest release is v0.15.0 from 2026-10-15.

## The V1 shim was one binary doing four jobs

The containerd shim is where hcsshim becomes a running process rather than a library, and the version history here is a redesign.

The V1 shim, containerd-shim-runhcs-v1, is described as a single, monolithic binary that handles LCOW, meaning Linux Containers on Windows, Hyper-V WCOW meaning Windows Containers on Windows, process-isolated WCOW, and host-process containers. That is four quite different isolation models in one program.

The build is a cross-compile with GOOS set to windows, and the resulting binary has to sit in the same directory as containerd itself:

```powershell
C:\> $env:GOOS="windows"
C:\> go build .\cmd\containerd-shim-runhcs-v1
```

The architecture note is the one to understand. Contrary to the typical Linux architecture of shim then runc, the runhcs shim is used both to launch and manage the lifetime of containers. On Linux, the shim is a thin process supervisor and runc does the work; on Windows, the shim is the thing talking to HCS, and there is no separate OCI runtime binary in the same sense.

That inversion is why the code is where it is. The shim has to hold the container lifecycle, the sandbox lifecycle and the registry of system objects that HCS hands back, and the HCS API on Windows is a COM-style interface with handle-based system objects rather than the file-descriptor and cgroup model Linux runtimes assume.

## The V2 shims split one binary into three, and only one has shipped

The V2 shims are the rewrite of the Windows containerd shim, and the README is unusually candid about the state of that work.

The monolith is split into focused, per-platform shims, each backed one to one by a sandbox. The V2 model splits responsibilities across the two APIs containerd now provides. The Sandbox API manages the sandbox, and the Task API manages the containers and processes running inside it. Internally each V2 shim implements these as separate sandbox and task services, alongside an auxiliary shimdiag service used for diagnostics.

All three shims honour the same CRI pod model. A task annotated with io.kubernetes.cri.container-type set to sandbox is treated as the pause or infra container that creates the pod, and sibling workload tasks set the annotation to container and reference their pause via io.kubernetes.cri.sandbox-id. What a sandbox physically corresponds to depends on the shim.

The three variants and their status:

containerd-shim-lcow-v2 runs Linux containers on Windows in a Linux utility VM, and each shim instance is backed by a single UVM. It supports running multiple pods in the same UVM, so one shim instance may host more than one CRI pod. Its implementation directory exists, its build tag is lcow, and it requires Windows Server 2025 build 26100 or later.

containerd-shim-wcow-v2 runs Hyper-V isolated Windows containers in a Windows utility VM, with the implementation listed as coming soon and the build tag wcow.

containerd-shim-process-v2 runs process-isolated Windows Server containers and host process containers directly on the host with no utility VM, where the sandbox is a pause container that owns the pod's shared resources such as the network namespace and keeps them alive while siblings start, stop or are replaced. Its implementation is also listed as coming soon, with the build tag process.

So of the three, one is real today. Anyone planning a Windows Server fleet should plan around LCOW, and the platform requirement is the harder constraint than the build tag.

## Building the V2 shims, where the build tag is not optional

The V2 shim sources are guarded by the build tags, so the tag must be passed to go build. The example given in the documentation is the LCOW shim with the lcow tag, on a Windows shell that first sets GOOS to windows, so the shape of the invocation is the same GOOS assignment shown above with an added -tags lcow flag and the containerd-shim-lcow-v2 package path.

Forgetting the tag is the obvious failure mode, and it fails at build time rather than at runtime, which is the friendlier version of the problem.

The Linux guest agent is built the other way round, by setting GOOS to linux and building out of ./cmd/gcs:

```powershell
C:\> $env:GOOS="linux"
C:\> go build .\cmd\gcs\
```

or on a Linux machine, where the same build is a plain go build of the package. If you want the agent packaged inside a rootfs to boot with the other tools, you need to supply that rootfs, and the documentation suggests exporting one from a container with docker pull busybox, docker run to create a container named base_image_container, and a docker export piped through gzip, then a make all. The expected output in the ./out folder is a delta.tar.gz, an initrd.img and a rootfs.tar.gz.

The Makefile shows the C side of the build too. The CFLAGS are -O2 -Wall, the binaries are linked statically and stripped, and kernel module loading in the init is off by default with KMOD set to 0, with an alternative that links -lkmod and defines -DMODULES=1.

## Wiring the shim into containerd and trying it with ctr

The shim has to be in the same directory as containerd, and the default configuration file can be generated by containerd itself:

```powershell
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii
```

That generated file will already have the shim set as the default runtime for CRI interactions, which removes the usual step of hand-editing the runtime stanza.

To trial it with ctr.exe, the command passes the runtime explicitly:

```powershell
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!"
```

The runtime name, io.containerd.runhcs.v1, is the identifier that ties the invocation to the shim binary. The nanoserver image is a reasonable choice for a smoke test on Windows.

The dependency picture in go.mod explains what the shim leans on. The containerd API and containerd v2 packages are direct requirements, alongside the ttrpc runtime, the containerd cgroups package, containerd go-runc, and the OCI runtime spec and opencontainers/runc. The networking side brings in the Microsoft go-winio library, which is the standard way to talk to Windows named pipes, plus the linuxkit virtsock package for the virtio socket transport used to reach the guest, and there is a vendored/ directory in the repository, so a build can run without network access to the module proxy.

## Where hcsshim stops and the alternatives start

The honest comparison is with the other approaches to Windows containers, and the difference is in what owns the lifecycle.

One alternative is to use HCS directly from your own code, which the README notes is possible since the repository can be used as a library of sorts to call the HCS apis. The trade is that you then own the system object bookkeeping, the job and utility VM management, and the layer of behaviour that the shim already implements, which is the layer that keeps containerd's view of the world consistent with the host's.

Another is the runhcs V1 shim versus the V2 shims, which is a design change rather than a different product. The V1 model is a single service implementing only the Task API and managing both sandbox and container lifecycles through it. The V2 model splits the two responsibilities across the Sandbox API and the Task API, with a separate shimdiag service for diagnostics. The benefit of the split is that each shim instance maps to exactly one sandbox, which makes the containerd contract easier to reason about, and the cost is that the rewrite has to be finished, which it has not been for two of the three variants.

The practical gap for most users is that hcsshim is not how you run Windows containers. You run them with Docker or with containerd configured to use the runhcs shim, and the runtime already points at these binaries. hcsshim matters to you if you are changing the runtime, adding a new isolation model, or working on the Windows container stack itself.

## Conclusion

Adopt hcsshim if you are working on Windows container internals, because it is the only implementation of the HCS and HNS interfaces available as a Go library and it ships the shim that containerd actually launches. Do not adopt it as a way to run containers, since it is a library and a shim, not a runtime, and the ordinary way to get Windows containers is Docker or containerd with the runhcs shim already selected. Before you build the V2 shims, note that only the LCOW variant is implemented while the WCOW and process variants are listed as coming soon, and that the LCOW shim requires Windows Server 2025 build 26100 or later, which excludes most current Windows Server installations.

## FAQ

### What is hcsshim and what is it used for?

It is the Golang interface for using the Windows Host Compute Service to launch and manage Windows Containers, plus the Host Network Service interface and the guest agent code used to support Linux Hyper-V containers. It is primarily used in the Moby and Containerd projects, but can be used by other projects as well.

### How do I build the runhcs containerd shim?

Set GOOS to windows and build the shim package, with the binary placed in the same directory as containerd. A default containerd configuration can be generated with .\containerd.exe config default piped to config.toml, and that file already sets the shim as the default runtime for CRI interactions.

### What is the difference between the V1 and V2 containerd shims?

The V1 shim is a single monolithic binary handling LCOW, Hyper-V WCOW, process-isolated WCOW and host-process containers through the Task API alone. The V2 shims split into per-platform shims backed one to one by a sandbox, with the Sandbox API managing the sandbox and the Task API managing containers and processes inside it, plus a shimdiag service for diagnostics.

### Which V2 shims are actually available in hcsshim?

Only containerd-shim-lcow-v2 is implemented, with the lcow build tag and a platform requirement of Windows Server 2025 build 26100 or later. containerd-shim-wcow-v2 and containerd-shim-process-v2 are both listed with their implementation marked as coming soon.

### How do I build the Linux guest agent for hcsshim?

Set GOOS to linux and build out of ./cmd/gcs, either with go build .\cmd\gcs\ on Windows or go build ./cmd/gcs on a Linux machine. To package it in a rootfs you need to supply one, for example by exporting a busybox container and running make all, which produces delta.tar.gz, initrd.img and rootfs.tar.gz in the ./out folder.

## Sources

- [Issues](https://github.com/microsoft/hcsshim/issues)
- [License: MIT](https://github.com/microsoft/hcsshim/blob/main/LICENSE)
- [microsoft/hcsshim on GitHub](https://github.com/microsoft/hcsshim)
- [README](https://github.com/microsoft/hcsshim/blob/main/README.md)
- [Releases](https://github.com/microsoft/hcsshim/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/microsoft-hcsshim
