Project: containerd (main branch, commit 35871e04a)
Modules: 2 Go modules (github.com/containerd/containerd/v2 + github.com/containerd/containerd/api)
Analysis date: February 11, 2026
Tool: depstat (built from source)
Containerd is a CNCF graduated container runtime with a 2-module repository (main + api). This analysis uses depstat to profile dependency scope, depth, cycles, archived dependencies, and version-to-version change trends.
| Metric | Value |
|---|---|
| Direct dependencies | 152 |
| Transitive dependencies | 270 |
| Total dependencies | 293 |
| Max dependency depth | 11 |
| Non-test dependencies | 243 |
| Test-only dependencies | 50 |
| Dependency cycles | 18 (11 two-node) |
| Archived dependencies | 14 |
- Broad dependency surface. 293 total dependencies with 152 direct deps reflects containerd's role as an integration point for container ecosystem components (OCI, CRI, CNI, Windows HCS, encryption, NRI, etc.).
- Moderate cycle count. 18 cycles with 3 containerd-internal (hcsshim, imgcrypt, zfs mutually depend on containerd/v2), plus external OTel, protobuf, and gRPC cycles.
- Dependency diet from v2.1.0 to v2.2.1. Net reduction of 23 deps (37 removed, 14 added), notably dropping the entire etcd client stack and legacy gRPC middleware.
- 14 archived dependencies —
pkg/errors,json-iterator/go,opencensus,golang/mock, and Windows-specificStackExchange/wmiare priorities for replacement.
Containerd uses a 2-module repository (no go.work):
github.com/containerd/containerd/
├── go.mod -> github.com/containerd/containerd/v2
└── api/go.mod -> github.com/containerd/containerd/api
The main module containerd/v2 has 153 outgoing edges — the largest fan-out node in the graph. It directly depends on a wide array of containerd sub-projects, OCI components, Kubernetes CRI/kubelet APIs, and platform-specific backends (HCS for Windows, ZFS, etc.).
The api module is a lightweight protobuf/gRPC definitions module depended on by the main module.
| Metric | Value |
|---|---|
| Direct Dependencies | 152 |
| Transitive Dependencies | 270 |
| Total (deduplicated) | 293 |
| Max Dependency Depth | 11 |
| Category | Count |
|---|---|
| Non-test | 243 |
| Test-only | 50 |
| Combined | 293 |
| Rank | Module | In-Degree | Out-Degree |
|---|---|---|---|
| 1 | go (stdlib) |
70 | 0 |
| 2 | golang.org/x/sys |
65 | 1 |
| 3 | github.com/davecgh/go-spew |
37 | 0 |
| 4 | github.com/stretchr/testify |
37 | 4 |
| 5 | google.golang.org/protobuf |
37 | 3 |
| 6 | gopkg.in/yaml.v3 |
37 | 1 |
| 7 | github.com/pmezard/go-difflib |
33 | 0 |
| 8 | golang.org/x/net |
31 | 5 |
| 9 | github.com/google/go-cmp |
29 | 1 |
| 10 | golang.org/x/text |
26 | 4 |
| Rank | Module | Out-Degree | In-Degree |
|---|---|---|---|
| 1 | github.com/containerd/containerd/v2 |
153 | 3 |
| 2 | github.com/Microsoft/hcsshim |
114 | 4 |
| 3 | github.com/containerd/imgcrypt/v2 |
58 | 1 |
| 4 | k8s.io/client-go |
54 | 1 |
| 5 | github.com/containernetworking/plugins |
48 | 1 |
| 6 | github.com/intel/goresctrl |
46 | 1 |
| 7 | k8s.io/apimachinery |
43 | 4 |
| 8 | github.com/containerd/zfs/v2 |
35 | 1 |
| 9 | google.golang.org/grpc |
35 | 22 |
| 10 | github.com/containerd/nri |
32 | 1 |
Figure 1. Full dependency graph:
| Metric | Value |
|---|---|
| Total cycles | 18 |
| 2-node cycles | 11 |
| Cycle | Nature |
|---|---|
Microsoft/hcsshim ↔ containerd/containerd/v2 |
Internal (Windows backend) |
containerd/containerd/v2 ↔ containerd/imgcrypt/v2 |
Internal (encryption plugin) |
containerd/containerd/v2 ↔ containerd/zfs/v2 |
Internal (ZFS snapshotter) |
golang/protobuf ↔ google.golang.org/protobuf |
External (protobuf) |
prometheus/client_golang ↔ prometheus/common |
External (Prometheus) |
stretchr/objx ↔ stretchr/testify |
External (testing) |
opentelemetry.io/auto/sdk ↔ opentelemetry.io/otel |
External (OTel) |
opentelemetry.io/otel ↔ opentelemetry.io/otel/metric |
External (OTel) |
opentelemetry.io/otel ↔ opentelemetry.io/otel/trace |
External (OTel) |
golang.org/x/crypto ↔ golang.org/x/net |
External (Go stdlib) |
genproto/googleapis/api ↔ google.golang.org/grpc |
External (gRPC) |
| Module | Cycle Count |
|---|---|
go.opentelemetry.io/otel |
7 |
github.com/containerd/containerd/v2 |
6 |
github.com/Microsoft/hcsshim |
4 |
go.opentelemetry.io/auto/sdk |
4 |
go.opentelemetry.io/otel/metric |
4 |
3 cycles are containerd-internal (hcsshim, imgcrypt, zfs all mutually depend on containerd/v2). The remainder are external ecosystem cycles.
14 archived dependencies detected:
| Module | Version | Repository |
|---|---|---|
StackExchange/wmi |
v0.0.0-2019... | GitHub |
census-instrumentation/opencensus-proto |
v0.2.1 | GitHub |
client9/misspell |
v0.3.4 | GitHub |
golang/mock |
v1.1.1 | GitHub |
google/btree |
v1.1.3 | GitHub |
google/gofuzz |
v1.2.0 | GitHub |
gregjones/httpcache |
v0.0.0-2019... | GitHub |
json-iterator/go |
v1.1.12 | GitHub |
mitchellh/go-homedir |
v1.1.0 | GitHub |
mndrix/tap-go |
v0.0.0-2017... | GitHub |
pkg/errors |
v0.9.1 | GitHub |
rcrowley/go-metrics |
v0.0.0-2020... | GitHub |
go.opencensus.io |
v0.24.0 | GitHub |
golang/lint |
v0.0.0-2019... | GitHub |
Priority replacements:
pkg/errors→ stdliberrors/fmt.Errorfwith%wjson-iterator/go→encoding/jsonorgo-jsonopencensus→ already being superseded by OTelgolang/mock→go.uber.org/mockStackExchange/wmi→github.com/yusufpapurcu/wmi(maintained fork, used by hcsshim)google/gofuzz→sigs.k8s.io/randfill(already added in v2.2.1)
| Metric | v2.1.0 | v2.2.1 | Delta |
|---|---|---|---|
| Direct Deps | 144 | 152 | +8 |
| Transitive Deps | 290 | 264 | -26 |
| Total Deps | 309 | 286 | -23 |
| Max Depth | 11 | 11 | ±0 |
Module graph: +14 added, -37 removed, ~82 version changes
- Etcd client stack removed —
go.etcd.io/etcd/api/v3,client/pkg/v3,client/v2,client/v3,pkg/v3,raft/v3,server/v3(7 etcd modules) - Legacy gRPC ecosystem —
grpc-ecosystem/go-grpc-middlewarev1,go-grpc-prometheus,grpc-gatewayv1 - Auth/OIDC stack —
coreos/go-oidc,pquerna/cachecontrol - Misc —
containerd/containerdv1 (self-reference),syndtr/gocapability(replaced bymoby/sys/capability)
- Wasm runtime —
tetratelabs/wazero(WebAssembly support) - Plugin system —
knqyf263/go-plugin(Go plugin framework) - Security —
cyphar/filepath-securejoin,google/certtostore - K8s modernization —
sigs.k8s.io/randfill,sigs.k8s.io/structured-merge-diff/v6 - Platform —
moby/sys/capability(replacessyndtr/gocapability)
Figure 2. Diff graph (v2.1.0 → v2.2.1):
Directly depended on by 23 modules (2 containerd + 21 external).
Core RPC transport for containerd's plugin architecture (ttrpc/gRPC), CRI API, and image services. Both containerd/v2 and containerd/api directly depend on gRPC.
Figure 3. Why-trace for gRPC:
Directly depended on by 16 modules (1 containerd + 15 external).
Distributed tracing for containerd operations. Only containerd/v2 directly depends on OTel; it also enters via hcsshim, imgcrypt, and gRPC instrumentation.
Figure 4. OTel dependency subgraph:
Directly depended on by 4 modules: containerd/v2, Microsoft/hcsshim, containerd/zfs/v2, k8s.io/apiserver.
Used for metadata storage. Enters via direct dependency and also through hcsshim and the k8s apiserver stack.
Figure 5. Why-trace for bbolt:
Directly depended on by 8 modules (1 containerd + 7 external).
Metrics instrumentation. Containerd/v2 directly depends on it; also enters via hcsshim, docker/go-metrics, intel/goresctrl, k8s apiserver/kubelet.
Figure 6. Why-trace for Prometheus client:
Directly depended on by 6 modules (1 containerd + 5 external).
Containerd's error classification library, used by containerd/v2, hcsshim, imgcrypt, zfs, containernetworking/plugins, and errdefs/pkg.
Figure 7. Why-trace for errdefs:
Directly depended on by 10 modules (1 containerd + 9 external).
Core OCI runtime specification. Enters through cgroups, go-runc, hcsshim, nri, imgcrypt, intel/goresctrl, and more.
Figure 8. Why-trace for runtime-spec:
- Replace archived dependencies — prioritize
pkg/errors,json-iterator/go,opencensus, andgolang/mock(see Section 6). - Address internal cycles — the 3 containerd-internal cycles (hcsshim ↔ containerd, imgcrypt ↔ containerd, zfs ↔ containerd) increase build complexity. Consider extracting shared interfaces to break these cycles.
- Track hcsshim fan-out —
Microsoft/hcsshimhas 114 outgoing edges and is the second-largest dependency node. It brings in significant transitive weight. - Continue etcd removal — v2.2.1 removed the etcd client stack. Verify no residual etcd dependencies remain in transitive paths.
- Monitor test-only deps — 50 test-only dependencies is notable; periodic pruning can reduce CI complexity.
All commands run with -d /path/to/containerd:
# Stats
depstat stats --json -d /path/to/containerd
depstat stats --split-test-only --json -d /path/to/containerd
# Graph
depstat graph --svg -d /path/to/containerd > containerd-full-graph.svg
depstat graph --top both -d /path/to/containerd
# Cycles
depstat cycles --summary --json -d /path/to/containerd
# Archived
GITHUB_TOKEN=$(gh auth token) depstat archived --json -d /path/to/containerd
# Diff
depstat diff v2.1.0 v2.2.1 --verbose -d /path/to/containerd
depstat diff v2.1.0 v2.2.1 --svg -d /path/to/containerd > containerd-diff-v21-v221.svg
# Why-traces
depstat why google.golang.org/grpc --svg -d /path/to/containerd > containerd-why-grpc.svg
depstat graph -p go.opentelemetry.io/otel --svg -d /path/to/containerd > containerd-why-otel.svg
depstat why go.etcd.io/bbolt --svg -d /path/to/containerd > containerd-why-bbolt.svg
depstat why github.com/prometheus/client_golang --svg --max-paths 50 -d /path/to/containerd > containerd-why-client_golang.svg
depstat why github.com/containerd/errdefs --svg -d /path/to/containerd > containerd-why-errdefs.svg
depstat why github.com/opencontainers/runtime-spec --svg -d /path/to/containerd > containerd-why-runtime-spec.svg