Generated by depstat at commit
643e407efefon branchmaster(the v1.37 development cycle). Analysis date: 2026-06-06. Compared against:v1.36.1(latest stable patch of the 1.36 line). depstat version:45eb8b409b5280a128d6bcbc974952c599954e1d(Fix why --svg/--dot timeout on highly-connected deps like OTel).
| Metric | Value |
|---|---|
| Total unique dependencies | 269 |
| Direct dependencies | 187 |
| Transitive dependencies | 234 |
| Test-only dependencies | 34 |
| Non-test dependencies | 235 |
| Dependency graph max depth | 18 |
| Dependency cycles | 17 |
| Archived dependencies | 5 |
| Main modules (go.work) | 34 (1 root + 33 staging) |
Direct and transitive overlap — a module can be required both directly by a workspace module and transitively through others. Test-only (34) + non-test (235) partition the 269 total exactly.
- The total rose +14 (255 → 269), but that is mostly a counting artifact — not real new surface. depstat counts module paths, and the net +14 is exactly the
go-openapifamily's 14 new module paths: 12swag/*sub-modules + 2go-openapi/testifymodules (all v0.25.4), produced when go-openapi split its formerly-monolithicswagmodule into per-directory modules. Same functionality, more nodes — no new upstream projects. The only genuinely-new non-go-openapi modules number 3 (golang.org/x/perf+aclements/go-moremath, andotel/metric/x), and they are cancelled one-for-one by the 3 removals (§7.2). So the distinct-upstream-project count is effectively flat — a softer reading than the raw "+14", and a contrast with the previous cycle, which trimmed 11 outright. (The +8 direct / +12 transitive split moves with the same go-openapi additions.) - The swag split, and its upside. go-openapi re-published
swag's subdirectories as 12 independent module paths (11 of them vendored, plus ajsonutils/fixtures_testhelper;swagitself v0.23.0 → v0.25.4) so callers import only the piece they need (swag/conv,swag/jsonutils,swag/mangling, …). The payoff is real: it let Kubernetes drop swag's old reflection-based helpersmailru/easyjson,josharian/intern, andstoewer/go-strcase(§7.4). So by distinct-project count the tree is arguably leaner, even as the module count rose. github.com/cenkalti/backoff/v4is fully retired. The previous analysis flagged it as a vendor-only leftover after the v5 migration; it is now gone from the module graph entirely — the migration completed.github.com/golang/groupcacheremoved — an unwanted-list module eliminated — along withgithub.com/grpc-ecosystem/go-grpc-middleware.- etcd jumped to a 3.7 release candidate:
go.etcd.io/etcd/{api,client/pkg,client,pkg,server}/v3v3.6.8 → v3.7.0-rc.0,raft/v3→ v3.7.0-rc.1,bbolt→ v1.5.0-rc.0. Master is now tracking pre-release etcd ahead of the 1.37 storage work. - gRPC v1.79.3 → v1.81.1; OpenTelemetry core v1.41.0 → v1.44.0 (contrib instrumentation v0.65 → v0.68); a broad
golang.org/x/*refresh. golang.org/x/netpinned to a HEAD pseudo-version (v0.55.1-0.20260602153038-42abb857022c) to pick up the Go 1.27 HTTP/2 "wrap" fixes — a forward-looking toolchain-compatibility pin, not yet a tagged release.- 17 cycles, down from 19. The previously-detected
onsi/ginkgo/v2 ↔ onsi/gomegaandstretchr/objx ↔ stretchr/testifytest-framework cycles are gone — only the forward edges survive; the reverse requirements dropped out at gomega v1.40.0 / objx v0.5.2. All 17 remaining cycles are upstream; OpenTelemetry accounts for 8. - Archived count steady at 5, but the membership changed.
github.com/kr/ptydropped out (the call sites moved tocreack/pty);github.com/envoyproxy/protoc-gen-validatev1.3.3 newly appears — it is simultaneously archived upstream and on Kubernetes' unwanted list. sigs.k8s.io/randfill(v1.0.0) has reached 54 fan-in. Thegoogle/gofuzzreplacement that the last analysis flagged as "in progress" is now the standard —gofuzzhas 0 first-party imports and survives only as a transitive dep ofjson-iterator/go.github.com/go-logr/logr(v1.4.3) remains the single highest-fan-in non-plumbing external library — 79 direct dependents (63k8s.io/*).gopkg.in/yaml.v3fan-in fell 91 → 81 (k8s.io 54 → 46) as modules migrate togo.yaml.in/yamlandsigs.k8s.io/yaml; it stays on the unwanted list and persists purely transitively via etcd, OTel, testify, and Prometheus.- Go toolchain steady at 1.26.0 — no bump in this window (the 1.25 → 1.26 jump landed in the previous cycle).
Kubernetes uses a go.work monorepo with vendored dependencies and a staging publication mechanism unique in the Go ecosystem.
k8s.io/kubernetes/
├── go.work -> workspace covering root + 33 staging modules (go 1.26.0)
├── go.mod -> k8s.io/kubernetes (root module)
├── vendor/ -> vendored copy of all external dependencies (217 modules)
└── staging/src/ -> 33 k8s.io/* staging repos
├── k8s.io/api/
├── k8s.io/apimachinery/
├── k8s.io/apiserver/
├── k8s.io/client-go/
└── ... 29 more
Key architectural properties:
- All
k8s.io/*staging modules are part of the workspace and share a single vendor directory. - External dependencies are vendored at the root and deduplicated across all 34 modules.
depstattraverses the fullgo.workgraph, not just the root module.
34 modules detected in go.work (unchanged set since v1.36.1 — no new staging modules in 1.37-dev yet; cri-streaming and streaming, new last cycle, are now established):
k8s.io/api, k8s.io/apiextensions-apiserver, k8s.io/apimachinery, k8s.io/apiserver, k8s.io/cli-runtime, k8s.io/client-go, k8s.io/cloud-provider, k8s.io/cluster-bootstrap, k8s.io/code-generator, k8s.io/component-base, k8s.io/component-helpers, k8s.io/controller-manager, k8s.io/cri-api, k8s.io/cri-client, k8s.io/cri-streaming, k8s.io/csi-translation-lib, k8s.io/dynamic-resource-allocation, k8s.io/endpointslice, k8s.io/externaljwt, k8s.io/kms, k8s.io/kube-aggregator, k8s.io/kube-controller-manager, k8s.io/kube-proxy, k8s.io/kube-scheduler, k8s.io/kubectl, k8s.io/kubelet, k8s.io/kubernetes, k8s.io/metrics, k8s.io/mount-utils, k8s.io/pod-security-admission, k8s.io/sample-apiserver, k8s.io/sample-cli-plugin, k8s.io/sample-controller, k8s.io/streaming
Direct Dependencies: 187
Transitive Dependencies: 234
Total (deduplicated): 269
Max Depth: 18
Test-only: 34
Non-test: 235
Test-only fraction: 34 of 269 total dependencies (12.6%) are test-only — up 3 since the 1.36 line (31), tracking the go-openapi/testify/v2 and golang.org/x/perf test additions. Max depth dropped by one (19 → 18).
Fan-in = number of edges in go mod graph pointing into a package (a proxy for how many modules pull it). Higher fan-in = more structurally load-bearing. The synthetic go toolchain node (155) tops the raw list and is excluded as plumbing.
| Rank | Fan-in | Module |
|---|---|---|
| 1 | 97 | github.com/davecgh/go-spew |
| 2 | 90 | github.com/pmezard/go-difflib |
| 3 | 88 | google.golang.org/protobuf |
| 3 | 88 | github.com/stretchr/testify |
| 5 | 83 | gopkg.in/yaml.v3 |
| 6 | 79 | github.com/go-logr/logr |
| 7 | 63 | github.com/google/go-cmp |
| 8 | 61 | go.yaml.in/yaml/v2 |
| 9 | 54 | sigs.k8s.io/randfill 🆕 |
| 9 | 54 | go.yaml.in/yaml/v3 🆕 |
| 9 | 54 | github.com/modern-go/reflect2 |
| 9 | 54 | github.com/modern-go/concurrent |
| 13 | 53 | github.com/json-iterator/go |
| 13 | 53 | github.com/google/uuid |
| 15 | 52 | sigs.k8s.io/structured-merge-diff/v6 |
| 15 | 52 | sigs.k8s.io/json |
| 15 | 52 | gopkg.in/inf.v0 |
| 15 | 52 | google.golang.org/genproto/googleapis/rpc |
| 15 | 52 | github.com/x448/float16 |
| 20 | 51 | sigs.k8s.io/yaml |
| 20 | 51 | github.com/spf13/pflag |
| 20 | 51 | github.com/fxamacker/cbor/v2 |
| 23 | 49 | go.opentelemetry.io/otel |
| 24 | 48 | google.golang.org/grpc |
⚠️ = listed inhack/unwanted-dependencies.json; 🆕 = notable mover vs. the previous analysis.
Two structural shifts stand out versus the prior cycle:
sigs.k8s.io/randfill(54) has entered the top tier. It is the actively-developed replacement for the archivedgithub.com/google/gofuzz, and its fan-in now rivals themodern-goandjson-iteratorcluster.- The YAML story is fragmenting deliberately.
go.yaml.in/yaml/v2(61) andgo.yaml.in/yaml/v3(54) — the maintained canonical paths — now sit alongside the still-present-but-unwantedgopkg.in/yaml.v3(83). The high fan-in of the unwantedgo-spew(97),yaml.v3(83), andjson-iterator/go(53) continues to reflect how deeply embedded these are transitively (testify, etcd, OTel all require them).
17 cycles detected (down from 19 in the previous analysis). Every cycle originates in upstream ecosystem packages; Kubernetes' own k8s.io/* staging repos maintain perfectly acyclic internal layering.
| Cycle Length | Count |
|---|---|
| 2 | 9 |
| 3 | 4 |
| 4 | 3 |
| 5 | 1 |
| # | Cycle |
|---|---|
| 1 | github.com/golang/protobuf → google.golang.org/protobuf → github.com/golang/protobuf |
| 2 | github.com/prometheus/client_golang → github.com/prometheus/common → github.com/prometheus/client_golang |
| 3 | go.opentelemetry.io/auto/sdk → go.opentelemetry.io/otel → go.opentelemetry.io/auto/sdk |
| 4 | auto/sdk → otel → otel/metric → auto/sdk |
| 5 | auto/sdk → otel/trace → otel → auto/sdk |
| 6 | auto/sdk → otel/trace → otel → otel/metric → auto/sdk |
| 7 | go.opentelemetry.io/otel → otel/metric → otel |
| 8 | otel → otel/metric → otel/trace → otel |
| 9 | go.opentelemetry.io/otel → otel/trace → otel |
| 10 | go.opentelemetry.io/otel/sdk → otel/sdk/metric → otel/sdk |
| 11 | golang.org/x/crypto → golang.org/x/net → golang.org/x/crypto |
| 12 | golang.org/x/crypto → golang.org/x/text → golang.org/x/tools → golang.org/x/net → golang.org/x/crypto |
| 13 | golang.org/x/crypto → golang.org/x/text → golang.org/x/mod → golang.org/x/tools → golang.org/x/net → golang.org/x/crypto |
| 14 | golang.org/x/mod → golang.org/x/tools → golang.org/x/mod |
| 15 | golang.org/x/mod → golang.org/x/tools → golang.org/x/net → golang.org/x/text → golang.org/x/mod |
| 16 | golang.org/x/net → golang.org/x/text → golang.org/x/tools → golang.org/x/net |
| 17 | google.golang.org/genproto/googleapis/api → google.golang.org/grpc → google.golang.org/genproto/googleapis/api |
The previous analysis listed onsi/ginkgo/v2 ↔ onsi/gomega and stretchr/objx ↔ stretchr/testify as cycles. Both are gone. Only the forward edges remain in the graph (ginkgo@v2.28.3 → gomega@v1.40.0, testify@v1.11.1 → objx@v0.5.2); the reverse requirements (gomega → ginkgo, objx → testify) are no longer present at the selected versions, so the loops no longer close. This is the entire 19 → 17 delta.
| Module | Cycle Count |
|---|---|
go.opentelemetry.io/otel |
7 |
golang.org/x/net |
5 |
golang.org/x/tools |
5 |
go.opentelemetry.io/auto/sdk |
4 |
go.opentelemetry.io/otel/metric |
4 |
go.opentelemetry.io/otel/trace |
4 |
golang.org/x/text |
4 |
golang.org/x/crypto |
3 |
golang.org/x/mod |
3 |
OpenTelemetry accounts for 8 of the 17 cycles. This is a known upstream design: the OTel Go SDK splits its API across otel, otel/metric, otel/trace, and the no-op auto/sdk, which mutually reference each other for interface definitions. All API modules resolve to v1.44.0, while auto/sdk v1.2.1 still pins down-level v1.38.0 requirements that Go's minimal-version selection raises to v1.44.0 (the dashed red edges below):
The golang.org/x/* packages account for 6 cycles through the well-known x/crypto ↔ x/net ↔ x/text ↔ x/tools ↔ x/mod web of mutual test and toolchain imports.
| Module | Version | Risk | Notes |
|---|---|---|---|
github.com/envoyproxy/protoc-gen-validate |
v1.3.3 | Medium | 🆕 Archived upstream and on the unwanted list. Superseded by buf.build/go/protovalidate; pulled transitively by google.golang.org/grpc (xDS/Envoy proto validation). |
github.com/flynn/go-shlex |
v0.0.0-20150515145356-3f9db97f8568 | Low | Simple shell lexer; stable, minimal attack surface. |
github.com/google/btree |
v1.1.3 | Low | Functionally complete B-tree; no security surface. |
github.com/google/gofuzz |
v1.0.0 | Low | First-party migration to sigs.k8s.io/randfill (54 fan-in) is complete (0 first-party uses); now survives only as a transitive dep of json-iterator/go. |
github.com/json-iterator/go |
v1.1.12 | Medium | 0 first-party imports; enters the build only via sigs.k8s.io/structured-merge-diff/v6 (server-side apply). The 53 fan-in is transitive (and pulls modern-go/*). See §10. |
- Removed from the archived set:
github.com/kr/pty— the call sites moved to the maintainedgithub.com/creack/pty, sokr/ptyleft the graph. - Newly flagged:
github.com/envoyproxy/protoc-gen-validatev1.3.3 — envoyproxy archived the repository in favor ofbuf.build/go/protovalidate. It was bumped v1.3.0 → v1.3.3 in this window even as it became archived.
The count is unchanged at 5, but it is not the same 5.
depstat archived can only verify GitHub-hosted repos. These are hosted elsewhere and were not checked programmatically (all are actively maintained):
bitbucket.org/bertimus9/systemstat, buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go, cyphar.com/go-pathrs 🆕, gonum.org/v1/gonum, google.golang.org/protobuf, gopkg.in/check.v1, gopkg.in/evanphx/json-patch.v4, gopkg.in/go-jose/go-jose.v2, gopkg.in/inf.v0, gopkg.in/natefinch/lumberjack.v2, gopkg.in/yaml.v3.
cyphar.com/go-pathrsis new this cycle — it is runc's safe-path-resolution library, pulled in through the container runtime stack.
┌────────────────────────┬──────────┬─────────────────┬─────────┐
│ Metric │ v1.36.1 │ master HEAD │ Delta │
├────────────────────────┼──────────┼─────────────────┼─────────┤
│ Direct Dependencies │ 179 │ 187 │ +8 │
│ Transitive Dependencies│ 222 │ 234 │ +12 │
│ Total (deduplicated) │ 255 │ 269 │ +14 │
│ Max Depth │ 19 │ 18 │ −1 │
└────────────────────────┴──────────┴─────────────────┴─────────┘
Module graph: +17 added, −3 removed, ~69 version changes. Vendor: +11 added, −3 removed, ~55 version changes. Note: v1.36.1 sits at 255 total — essentially identical to the master snapshot the previous analysis measured (the 1.36 line shipped at that surface). But the +14 is not genuinely new dependency surface — see §7.1: it is the
go-openapimodule-count expansion (one module re-published as many), with the handful of real new deps offset one-for-one by removals.
The 17 additions split into 14 go-openapi-family modules and 3 genuinely-new ones:
- 14 go-openapi — 12
swag/*sub-modules + 2go-openapi/testifymodules, all v0.25.4. This is a granularity change: go-openapi re-published one module as many, inflating the module count without adding a new upstream dependency or new functionality. - 3 genuinely new —
golang.org/x/perf, itsaclements/go-moremathstatistics dependency, and the experimentalotel/metric/x. These are exactly offset by the 3 removals in §7.2, so the count of distinct upstream projects is effectively flat.
Full list:
| Module | Category | Notes |
|---|---|---|
github.com/go-openapi/swag/conv |
OpenAPI | swag split into granular sub-modules (v0.25.4) |
github.com/go-openapi/swag/fileutils |
OpenAPI | " |
github.com/go-openapi/swag/jsonname |
OpenAPI | " |
github.com/go-openapi/swag/jsonutils |
OpenAPI | " |
github.com/go-openapi/swag/loading |
OpenAPI | " |
github.com/go-openapi/swag/mangling |
OpenAPI | " |
github.com/go-openapi/swag/netutils |
OpenAPI | " |
github.com/go-openapi/swag/stringutils |
OpenAPI | " |
github.com/go-openapi/swag/typeutils |
OpenAPI | " |
github.com/go-openapi/swag/yamlutils |
OpenAPI | " |
github.com/go-openapi/swag/cmdutils |
OpenAPI | " |
github.com/go-openapi/swag/jsonutils/fixtures_test |
OpenAPI | test fixture sub-module |
github.com/go-openapi/testify/v2 |
Test | go-openapi's vendored testify fork |
github.com/go-openapi/testify/enable/yaml/v2 |
Test | " |
golang.org/x/perf |
Benchmarking | benchmark/statistics tooling |
github.com/aclements/go-moremath |
Benchmarking | statistics lib pulled by x/perf |
go.opentelemetry.io/otel/metric/x |
Observability | experimental OTel metric extensions (pulled by otel/sdk/metric v1.44) |
| Module | Notes |
|---|---|
github.com/cenkalti/backoff/v4 |
v5 migration completed — previously a vendor-only leftover, now fully gone |
github.com/golang/groupcache |
Unwanted-list caching library eliminated |
github.com/grpc-ecosystem/go-grpc-middleware |
Removed (the /v2 and /providers/prometheus sub-modules remain) |
| Module | Before | After | Notes |
|---|---|---|---|
go toolchain |
1.26.0 |
1.26.0 |
Unchanged this cycle |
google.golang.org/grpc |
v1.79.3 |
v1.81.1 |
+2 minor |
go.opentelemetry.io/otel (+ metric/trace) |
v1.41.0 |
v1.44.0 |
core OTel |
go.opentelemetry.io/otel/sdk (+ sdk/metric) |
v1.40.0 |
v1.44.0 |
+4 |
go.opentelemetry.io/contrib/.../otel{restful,grpc,http} |
v0.65.0 |
v0.68.0 |
instrumentation |
go.etcd.io/etcd/*/v3 |
v3.6.8 |
v3.7.0-rc.0 |
release candidate |
go.etcd.io/raft/v3 |
v3.6.0 |
v3.7.0-rc.1 |
RC |
go.etcd.io/bbolt |
v1.4.3 |
v1.5.0-rc.0 |
RC |
golang.org/x/net |
v0.49.0 |
v0.55.1-0.20260602…42abb857022c |
HEAD pseudo-version (Go 1.27 http2 fixes) |
golang.org/x/crypto |
v0.47.0 |
v0.52.0 |
+ broad x/{sys,text,tools,mod,term,oauth2,sync,time} refresh |
github.com/go-openapi/swag |
v0.23.0 |
v0.25.4 |
drove the module split (§7.1) |
github.com/go-openapi/jsonpointer |
v0.21.0 |
v0.22.4 |
|
github.com/go-openapi/jsonreference |
v0.20.2 |
v0.21.4 |
|
github.com/google/cel-go |
v0.26.0 |
v0.27.0 |
CEL engine |
github.com/google/cadvisor |
v0.56.2 |
v0.57.0 |
cAdvisor |
github.com/moby/moby/api / client |
v1.52.0 / v0.2.1 |
v1.54.1 / v0.4.0 |
Moby split modules |
sigs.k8s.io/structured-merge-diff/v6 |
v6.3.2 |
v6.4.0 |
SSA core |
github.com/grpc-ecosystem/grpc-gateway/v2 |
v2.27.7 |
v2.29.0 |
|
cloud.google.com/go/compute/metadata |
v0.9.0 |
v0.7.0 |
rare downgrade, but not vendored → no build impact |
The
cloud.google.com/go/compute/metadatadowngrade (v0.9.0 → v0.7.0) is only a module-graph resolution shift: the module is not vendored at either ref, so nothing is compiled from it and there is no build impact. (It is a transitive requirement no vendored package imports; with module-graph pruning the graph-selected version can move either direction.)
Vendored Modules: 209 → 217 (+8)
Added (11): all eleven github.com/go-openapi/swag/* sub-modules @ v0.25.4
Removed (3): josharian/intern, mailru/easyjson, stoewer/go-strcase
Vendor-only removals (still in module graph, no longer vendored):
josharian/intern, mailru/easyjson, stoewer/go-strcase
The three vendor removals are the old swag dependencies: mailru/easyjson (reflection-based JSON), its helper josharian/intern, and stoewer/go-strcase (case conversion). The rewritten swag (v0.25.x) replaced them with its own conv/jsonutils/mangling sub-packages. They remain in the module graph as unselected transitive requirements but no vendored package imports them — the same divergence pattern the previous analysis flagged for backoff/v4 (now resolved).
Green = added, Red = removed, Yellow = version changed.
The full graph shows the characteristic hub-and-spoke structure: k8s.io/kubernetes at the center with its 187 direct edges, surrounded by a ring of staging repos each pulling 60–110 dependencies, and an outer shell of third-party libraries. The k8s.io staging cluster is densely interconnected but perfectly acyclic — all detected cycles originate in upstream ecosystem packages (§5).
Why-trace targets are chosen by fan-in rank (computed from go mod graph) plus architectural significance, excluding golang.org/x/* (toolchain cross-deps) and k8s.io/* (workspace-internal). The same seven targets as the previous analysis are used here so the two runs are directly comparable.
Fan-in rank: #6 | Direct dependents: 79 total (63 k8s.io/*) | Selected version: v1.4.3
go-logr/logr is the structured-logging interface used throughout Kubernetes and nearly all of its staging modules, decoupling logging call sites from the backend (klog/v2 is the concrete implementation). It remains the single highest-fan-in non-plumbing external library. Unchanged in version since v1.36.1; stable and actively maintained, with no replacement on the horizon.
Fan-in rank: #5 | Direct dependents: 81 total (46 k8s.io/*) | Selected version: v3.0.1
yaml.v3 is on Kubernetes' unwanted-dependencies list — the preferred alternatives are sigs.k8s.io/yaml and the maintained go.yaml.in/yaml/*. Its dependent count has fallen (91 → 81 total, 54 → 46 k8s.io/*) as workspace modules migrate, but it persists because major transitive dependencies still require it directly: go.etcd.io/etcd/*, go.opentelemetry.io/*, github.com/stretchr/testify, github.com/prometheus/common, github.com/google/cadvisor, and the gRPC-middleware packages. Eliminating it requires coordinated upstream changes.
Fan-in rank: #24 | Direct dependents: 48 total (31 k8s.io/*) | Selected version: v1.81.1
gRPC is Kubernetes' core RPC transport: the API server (aggregated APIs, CRI, CSI, device plugins), the etcd client, OTel exporters, and konnectivity all depend on it. Bumped v1.79.3 → v1.81.1 in this window.
Fan-in rank: #23 | Direct dependents: 49 total (35 k8s.io/*) | Selected version: v1.44.0
OTel is the tracing/metrics framework adopted for observability — the API server, kubelet, scheduler, and controller-manager all emit spans and metrics through it. The high k8s.io/* share (35 of 49) shows how pervasively the instrumentation is applied. Core OTel advanced v1.41.0 → v1.44.0 this cycle, and it is also pulled transitively by gRPC (which bundles OTel for metrics).
Direct dependents: 33 total (27 k8s.io/*) | Selected version: v1.23.2
Prometheus client_golang is the metrics-exposition library — every Kubernetes component exposes a /metrics endpoint in Prometheus format. Also pulled transitively by the gRPC middleware and the OTel→Prometheus bridge. Unchanged in version since v1.36.1.
Direct dependents: 20 total (19 k8s.io/*) | Selected version: v0.27.0
CEL (Common Expression Language) powers ValidatingAdmissionPolicy, authorization policy, and CRD validation rules. It is used only by apiserver-tier staging modules; the low absolute count (20) with a near-total k8s share (19) shows it is a first-party dependency with minimal transitive spread. Bumped v0.26.0 → v0.27.0.
Direct dependents: 16 total (15 k8s.io/*) | Selected version: v3.7.0-rc.0
etcd is Kubernetes' primary storage backend. The API server depends on etcd/client/v3 directly, and integration-test utilities pull it too. The low fan-in (16) reflects that only apiserver-tier modules deal with etcd directly. This cycle moved the entire etcd stack onto a 3.7 release candidate (v3.6.8 → v3.7.0-rc.0) — a notable choice to track pre-release storage on master.
Methodology note: each item below was checked against the actual module graph and first-party
.goimports at this HEAD — not inferred from package names. Notably, none of the unwanted/archived libraries are imported by first-party Kubernetes code anymore (all are transitive), which is what makes the levers below upstream-shaped.
- Re-pin
golang.org/x/netto a tagged release. It is currently a HEAD pseudo-version (v0.55.1-0.20260602…) carried for the Go 1.27 http2 "wrap" fixes. Move to the next taggedx/netonce those land in a release, to satisfyverify-vendor/supply-chain expectations. - Land the etcd 3.7 line on final tags before the 1.37 freeze. Master tracks
etcd/* v3.7.0-rc.0,raft v3.7.0-rc.1,bbolt v1.5.0-rc.0. Riding an RC on master is normal etcd co-development, but the pins should advance to GA (etcd 3.7.0, bbolt 1.5.0) before freeze. - Migrate
sigs.k8s.io/structured-merge-diff/v6offgithub.com/json-iterator/go— the single highest-leverage cleanup.json-iterator(archived) has zero first-party imports in Kubernetes; it enters the compiled build through exactly one importer —structured-merge-diff/v6(value.go,fieldpath/serialize*.go), used in server-side apply. SMD is a kubernetes-sigs library, so this is in-scope, and it cascades: droppingjson-iteratoralso removesgithub.com/modern-go/{concurrent,reflect2}(54 fan-in each) andgithub.com/google/gofuzz(which now survives only as json-iterator's transitive dep). Caveat: SMD uses json-iterator for SSA-serialization performance, so a replacement must be benchmarked. (prometheus/client_golangalso lists json-iterator in go.mod, but its vendored code never imports it.)
github.com/envoyproxy/protoc-gen-validate(archived + unwanted) — pulled bygoogle.golang.org/grpc(its xDS/Envoy proto validation), not by first-party code. Nothing to migrate directly; it drops when gRPC moves tobuf.build/go/protovalidate. Track the gRPC change.gopkg.in/yaml.v3(81 fan-in, unwanted) — also 0 first-party imports, trending down (91 → 81) as the ecosystem moves togo.yaml.in/yamlandsigs.k8s.io/yaml. Now purely transitive (etcd, OTel, testify, Prometheus), so removal depends on those upstreams. Keep blocking new direct uses in k8s code as policy.github.com/google/btree,github.com/flynn/go-shlex(archived, low risk) — monitor for supply-chain events; no action needed.
- First-party code is already clean — worth recording. Kubernetes' own packages import none of the high-fan-in unwanted/archived libraries:
go-spew,yaml.v3,json-iterator,gofuzz, andmodern-go/{concurrent,reflect2}all have 0 first-party imports. Every one persists purely transitively, so all remaining cleanup is upstream-driven (High/Medium above) — and on the first-party side, thegofuzz→randfillmigration is effectively done. github.com/davecgh/go-spew(97 fan-in, unwanted) — pulled bytestify(test scope); disappears if/when testify drops it.- Vendor-only removals (
mailru/easyjson,josharian/intern,stoewer/go-strcase) — removed fromvendor/but still in the module graph. Verify they don't re-vendor on the nextgo mod tidy; prune from go.mod if unneeded.
All commands were run from a detached git worktree of k8s.io/kubernetes pinned at commit 643e407efef84a7bd37ef23d9ed4ec0ddc123571 (Merge pull request #139532 from serathius/watchcache-waituntilfresh-cleanup), go 1.26.0.
depstat version: 45eb8b409b5280a128d6bcbc974952c599954e1d (built from sigs.k8s.io/depstat).
Fan-in ranking command (determines why-trace selection):
go mod graph | awk '{print $2}' | sed 's/@.*//' \
| grep -v '^k8s.io/' | grep -v '^golang.org/x/' \
| sort | uniq -c | sort -rn | head -25Why-trace targets (data-driven from fan-in, held constant vs. the prior run for comparability):
github.com/go-logr/logr(79, rank #6)gopkg.in/yaml.v3(81, rank #5 — unwanted, shown to explain persistence)google.golang.org/grpc(48, rank #24)go.opentelemetry.io/otel(49, rank #23)github.com/prometheus/client_golang(33)github.com/google/cel-go(20)go.etcd.io/etcd/client/v3(16)
Exact commands:
# Build depstat
cd $HOME/go/src/sigs.k8s.io/depstat && go build -o /tmp/depstat .
# From the kubernetes worktree root:
/tmp/depstat stats -d .
/tmp/depstat stats -d . --split-test-only
/tmp/depstat cycles -d .
/tmp/depstat cycles -d . --summary
GITHUB_TOKEN="$(gh auth token)" /tmp/depstat archived -d . --json
# Release diff (--vendor bundles module-level + vendor-level diff)
/tmp/depstat diff -d . v1.36.1 HEAD --vendor
# SVGs (graph/diff print a module-detection prefix -> awk-filter to the SVG)
/tmp/depstat graph -d . --svg | awk '/^<\?xml/{f=1} /^<svg/{f=1} f' > k8s-full-graph.svg
/tmp/depstat diff -d . v1.36.1 HEAD --svg | awk '/^<\?xml/{f=1} /^<svg/{f=1} f' > k8s-diff-v1361-master.svg
# Why-traces (why --svg emits clean SVG)
for t in github.com/go-logr/logr gopkg.in/yaml.v3 google.golang.org/grpc \
go.opentelemetry.io/otel github.com/prometheus/client_golang \
github.com/google/cel-go go.etcd.io/etcd/client/v3; do
slug="${t//\//_}"; slug="${slug//./_}"
/tmp/depstat why -d . "$t" --svg --max-paths 50 > "k8s-why-${slug}.svg"
done
# OTel cycles diagram is hand-authored (depstat cycles --svg is an unsupported placeholder):
# graphviz dot built from `depstat cycles` + the inter-OTel edges of `go mod graph`.
dot -Tsvg k8s-otel-cycles.dot -o k8s-otel-cycles.svg
# Direct-dependent counts
for t in github.com/go-logr/logr gopkg.in/yaml.v3 google.golang.org/grpc \
go.opentelemetry.io/otel github.com/prometheus/client_golang \
github.com/google/cel-go go.etcd.io/etcd/client/v3; do
go mod graph | grep " ${t}@" | awk -F'@' '{print $1}' | sort -u | wc -l
done