# Stargz Snapshotter moves pull time into run time, and v0.19.0 added a kubelet flag for it

> Stargz Snapshotter is an Apache-2.0 containerd snapshotter that lets a container start before its image has been pulled, fetching chunks on demand from a lazily-pullable eStargz image. It suits short-lived containers on high-latency networks, and since v0.19.0 it requires a specific kubelet flag or image verification silently does not happen.

**containerd/stargz-snapshotter** — Fast container image distribution plugin with lazy pulling

- Repository: https://github.com/containerd/stargz-snapshotter
- Website: https://github.com/containerd/containerd/issues/3731
- Stars: 1,602 · Forks: 162
- Language: Go
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/containerd-stargz-snapshotter

## The problem it names: pull is most of container startup

The README opens with a measurement rather than a feature list. It cites research showing that the pull operation accounts for 76 percent of container startup time, referencing a FAST '16 paper.

That number is the entire justification. In a default setup, containerd downloads every layer before the container runs, so on a high-latency link to a distant registry the work is serialised: network transfer first, then execution.

Stargz Snapshotter attacks that by making the pull concurrent with execution instead of prior to it. The README defines lazy pulling as a container running without waiting for the pull to complete, with the necessary chunks of the image fetched on demand.

Two things follow. First, this is a snapshotter, a containerd plugin that provides a filesystem view of images, not a distribution proxy or a registry-side change. Second, the reordering only helps if the image format supports it, which is what eStargz provides.

The project describes itself as a non-core sub-project of containerd, hosted in the containerd GitHub organisation with MAINTAINERS and a NOTICE.md.

## eStargz: a lazily-pullable format that still runs on Docker

eStargz is the image format this project proposes, documented in docs/stargz-estargz.md. Two properties matter for adoption.

The first is compatibility. The README states eStargz is compatible with OCI and Docker images, so it can be pushed to a standard registry such as ghcr.io. The format lives in the image rather than in a private registry extension, which is why there is a `nativeconverter/` directory in the repository and a list of pre-converted images in docs/pre-converted-images.md.

The second is that an eStargz image remains runnable on a runtime that knows nothing about eStargz, Docker included. An eStargz-converted layer is still a valid gzip or zstd layer with extra index metadata, so if you push one to a registry and pull it with plain Docker, it works, just without the laziness.

The format is based on stargz from CRFS and adds runtime optimisation and content verification. Those additions are what the snapshotter's prefetching and its integrity checking rely on.

If you run eStargz images but not this snapshotter, you have a compatible image with none of the benefit. The two pieces have to be deployed together.

## The containerd config: proxy_plugins plus the CRI snapshotter

Wiring it into containerd is a configuration change to the runtime's TOML. The README assumes containerd newer than v1.4.2 as the CRI runtime, and the block is:

```toml
version = 2

[proxy_plugins]
  [proxy_plugins.stargz]
    type = "snapshot"
    address = "/run/containerd-stargz-grpc/containerd-stargz-grpc.sock"
  [proxy_plugins.stargz.exports]
    root = "/var/lib/containerd-stargz-grpc/"

[plugins."io.containerd.grpc.v1.cri".containerd]
  snapshotter = "stargz"
  disable_snapshot_annotations = false
```

The mechanism is containerd's proxy plugin mechanism: containerd recognises the snapshotter by the socket address it listens on, and the exports root is where the snapshotter keeps its own state.

The second half is the CRI switch. Setting `snapshotter = "stargz"` makes Kubernetes use it, and `disable_snapshot_annotations = false` keeps the annotations that map layers back to their images, which the verification logic needs.

This is not Docker-only. The README points to separate install documentation covering containerd, CRI-O, Podman and systemd, plus an integration status document for community tools.

## Since v0.19.0 the kubelet needs an image service endpoint

Release v0.19.0, tagged on 2026-10-08, added a requirement that will silently degrade security if you miss it.

The README states that since v0.19.0 you must also pass `--image-service-endpoint=unix:///run/containerd-stargz-grpc/containerd-stargz-grpc.sock` to kubelet. Without it, the snapshotter cannot verify the DiffIDs advertised in the image configuration.

The README then explains what that means: it allows a maliciously crafted image with faked DiffIDs to be mounted to other containers that have those DiffIDs.

That is the sentence to hold on to. The endpoint lets the snapshotter perform image verification logic on CRI calls, and omitting the flag does not produce an error, it produces unverified images. An upgrade from v0.18.x to v0.19.0 therefore has a security step in it that will not announce itself in the logs.

If you are on an older release, this does not apply, but it is the reason to read the changelog before pinning a version. The details live in the kubelet configuration section of docs/overview.md.

## The benchmark trade: pull gets faster, run gets slower

The README describes its own benchmark results across three configurations, measured on GitHub Actions against GitHub Container Registry, based on Tintri's HelloBench.

`legacy` is containerd's default overlayfs snapshotter with unoptimised images from docker.io/library. The full image is pulled, so the pull operation is as long as it is.

`estargz-noopt` uses eStargz images with no optimisation. Here the pull improves because the container starts before the pull completes. But the README is explicit that the run operation gets worse, because every file access now costs a fetch from the registry.

`estargz` is the tuned case, where the drawback is mitigated by the snapshotter prefetching and caching the files likely to be accessed. The cost moves again: on first container creation the snapshotter waits for the prefetch to finish, so `create` sometimes takes longer than with other image types. The README's claim is that it is still shorter than downloading all files of all layers.

Two honest caveats are in the README as well. The histogram is pinned to a specific commit, and the maintainers note they sometimes see dispersion between runs because of network conditions and GitHub Actions instance location.

So the honest summary is that this moves cost rather than removing it, and which operations win depends on your container lifetime and your link latency.

## Four binaries, and an experimental IPFS path

The Makefile shows what the project actually produces. The CMD line lists four binaries: `containerd-stargz-grpc`, `ctr-remote`, `stargz-store` and `stargz-fuse-manager`.

`containerd-stargz-grpc` is the snapshotter daemon that listens on the socket in the containerd config. `stargz-store` is the content store holding fetched chunks, which is what `ctr-remote` talks to for remote image operations. `stargz-fuse-manager` handles the FUSE-based mounting, and the presence of `github.com/hanwen/go-fuse/v2` in go.mod confirms that path.

The build is Go 1.26.6 per go.mod, with containerd v2.4.1 as the direct dependency and k8s.io/api at 0.37.1 for the CRI side.

For trying it without configuring a node, the README points to prebuilt KinD node images:

```console
$ kind create cluster --name stargz-demo --image ghcr.io/containerd/stargz-snapshotter:0.12.1-kind
```

That specific example pins 0.12.1, while the README recommends kind binary v0.16.x or newer, and newer node images are published under the same ghcr namespace.

There is also an IPFS mode. The README marks it experimental and points to docs/ipfs.md, which is the right label to carry into a planning conversation.

## Where lazy pulling is the wrong answer

The benchmark case narrows this. The gain comes from not waiting for a full pull, which means it is largest for many containers starting over a slow link and smallest when there are few.

A handful of long-running pods on a fast local network is the wrong case. There is little serialised pull time to overlap, and the prefetch wait on first creation is a cost you pay for nothing.

The second wrong case is a workflow you do not control. Lazy pulling needs eStargz images. If your images come from a third party that will not convert them, you get the snapshotter with none of the benefit, plus the remote-fetch latency on every file access. Converting is the prerequisite, and there is no way around it.

The third is an environment where FUSE is unavailable or restricted. The snapshotter is a FUSE-based filesystem, and hardened or rootless configurations vary in what they permit.

The fourth is a decision about ownership. This is a non-core containerd sub-project, so it is maintained by a group rather than shipped as part of containerd itself, and upgrading it means running a daemon alongside your runtime on every node.

## Against pre-pulling, against image optimisation, and against a proxy

There are three other ways to attack the same 76 percent, and they differ in approach.

Pre-pulling with a warm node: keep a copy of every image on the node before it is needed, so the pull happens on your schedule rather than at startup. This costs node disk and needs a DaemonSet or equivalent to manage the cache. It has no format requirement and no daemon of its own, which is why it remains the common answer.

Image optimisation: make the images smaller. Multi-stage builds, distroless bases and pruning cut transfer time directly, without any runtime change. The README's own benchmark even copies from docker.io/library without optimisation as the baseline, which implies unoptimised images are the case being improved upon.

A registry-side proxy with local caching: pull through a caching registry that keeps layers warm near your nodes. This adds an infrastructure component and a network hop, and it solves the same problem for every runtime rather than only containerd.

Stargz's distinguishing claim is that it needs no warm cache and no extra infrastructure, and it works from a standard registry with standard image formats. Its cost is the per-file remote latency that the benchmark shows, and the operational weight of another daemon per node.

## Conclusion

Adopt Stargz Snapshotter when you run many short-lived containers on Kubernetes nodes with slow registry links and you can convert images to eStargz, since that is the case its benchmark shows a gain for. Do not adopt it for a small number of long-running pods, where the prefetch wait on first creation adds latency without amortising. Verify first that kubelet is started with `--image-service-endpoint=unix:///run/containerd-stargz-grpc/containerd-stargz-grpc.sock`, since without it the DiffIDs in the image configuration are not verified.

## FAQ

### How do I configure Stargz Snapshotter in containerd?

Add a proxy_plugins entry with type = "snapshot" pointing at /run/containerd-stargz-grpc/containerd-stargz-grpc.sock, then set snapshotter = "stargz" under the CRI containerd plugin with disable_snapshot_annotations = false. Run the stargz snapshotter daemon on the node as well.

### What is eStargz and do I need it?

eStargz is the lazily-pullable image format proposed by this project, based on CRFS stargz with additional runtime optimisation and content verification. You need it, since the snapshotter only gets lazy pulling from eStargz images, and an eStargz image still runs on plain Docker because it stays a valid OCI or Docker image.

### What changed in Stargz Snapshotter v0.19.0?

Since v0.19.0 you must pass --image-service-endpoint=unix:///run/containerd-stargz-grpc/containerd-stargz-grpc.sock to kubelet so the snapshotter can proxy CRI calls with image verification. Without it the DiffIDs in the image configuration are not verified, which the README says allows an image with faked DiffIDs to be mounted to other containers.

### Does lazy pulling make containers start faster?

It depends on the workload. The README's benchmark shows the pull improves because the container starts before the pull completes, while run gets slower because each file access needs a fetch from the registry. Using eStargz with optimisation mitigates the run drawback by prefetching likely accessed files, at the cost of a longer first create.

### Can I test Stargz Snapshotter with KinD?

Yes. Prebuilt node images are published, and the README gives kind create cluster --name stargz-demo --image ghcr.io/containerd/stargz-snapshotter:0.12.1-kind. The README recommends kind binary v0.16.x or newer for these images.

### What licence is Stargz Snapshotter released under?

It is released under the Apache License 2.0, with LICENSE and NOTICE.md at the repository root. This is a licensing note and not legal advice.

## Sources

- [containerd/stargz-snapshotter on GitHub](https://github.com/containerd/stargz-snapshotter)
- [License: Apache-2.0](https://github.com/containerd/stargz-snapshotter/blob/main/LICENSE)
- [Project website](https://github.com/containerd/containerd/issues/3731)
- [README](https://github.com/containerd/stargz-snapshotter/blob/main/README.md)
- [Releases](https://github.com/containerd/stargz-snapshotter/releases)

---

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