Project: etcd (main branch, commit a5649248231)
Modules: 10 Go modules analyzed (13 total; 3 tools modules auto-excluded by depstat)
Analysis date: February 11, 2026
Tool: depstat (built from source)
Etcd is a CNCF graduated distributed key-value store with a 13-module monorepo architecture. This analysis uses depstat to profile dependency scope, depth, cycles, archived dependencies, and change trends across the 10 non-tools modules (tools modules are excluded by default as they pull in linters and GCP SDK).
| Metric | All 10 Modules | Core 8 (excl. tests) |
|---|---|---|
| Direct dependencies | 87 | 81 |
| Transitive dependencies | 113 | 113 |
| Total dependencies | 141 | 139 |
| Max dependency depth | 12 | 12 |
| Metric | Value |
|---|---|
| Non-test dependencies | 123 |
| Test-only dependencies | 18 |
| Dependency cycles | 13 (7 two-node) |
| Archived dependencies | 8 |
- Lean dependency footprint. 141 total dependencies across 10 modules with a max depth of 12 — a well-managed graph for a project of this scope.
- Cycles are minimal and external. Only 13 cycles detected, all originating from external ecosystems (OTel, protobuf, prometheus, x/crypto). No etcd-internal cycles.
- Large dependency diet from v3.5.0 to v3.6.0. Net reduction of 51 deps (92 removed, 41 added), driven by removal of the HashiCorp stack and legacy gRPC/gateway v1 patterns.
- 8 archived dependencies should be tracked for replacement — notably
opentracing-go,pkg/errors,json-iterator/go, andgoogle/btree.
Etcd uses a 13-module monorepo (via go.work):
go.etcd.io/etcd/
├── go.mod -> go.etcd.io/etcd/v3
├── api/go.mod -> go.etcd.io/etcd/api/v3
├── cache/go.mod -> go.etcd.io/etcd/cache/v3
├── client/pkg/go.mod -> go.etcd.io/etcd/client/pkg/v3
├── client/v3/go.mod -> go.etcd.io/etcd/client/v3
├── etcdctl/go.mod -> go.etcd.io/etcd/etcdctl/v3
├── etcdutl/go.mod -> go.etcd.io/etcd/etcdutl/v3
├── pkg/go.mod -> go.etcd.io/etcd/pkg/v3
├── server/go.mod -> go.etcd.io/etcd/server/v3
├── tests/go.mod -> go.etcd.io/etcd/tests/v3
├── tools/mod/go.mod -> go.etcd.io/etcd/tools/v3 (excluded)
├── tools/rw-heatmaps/ -> go.etcd.io/etcd/tools/rw-heatmaps/v3 (excluded)
└── tools/testgrid/ -> go.etcd.io/etcd/tools/testgrid-analysis/v3 (excluded)
v3 (main)
├── tests/v3
│ ├── etcdctl/v3
│ ├── etcdutl/v3 -> server/v3
│ └── server/v3
├── etcdctl/v3 -> client/v3
├── etcdutl/v3 -> server/v3
├── server/v3
│ ├── client/v3 -> api/v3, client/pkg/v3
│ ├── pkg/v3 -> client/pkg/v3
│ └── api/v3
├── cache/v3 -> client/v3
└── tools/v3 (independent, pulls in linters + GCP SDK)
| Metric | Value |
|---|---|
| Direct Dependencies | 87 |
| Transitive Dependencies | 113 |
| Total (deduplicated) | 141 |
| Max Dependency Depth | 12 |
| Metric | Value |
|---|---|
| Direct Dependencies | 81 |
| Transitive Dependencies | 113 |
| Total (deduplicated) | 139 |
| Max Dependency Depth | 12 |
| Category | Count |
|---|---|
| Non-test | 123 |
| Test-only | 18 |
| Combined | 141 |
| Rank | Module | In-Degree | Out-Degree |
|---|---|---|---|
| 1 | go (stdlib) |
33 | 0 |
| 2 | golang.org/x/sys |
30 | 1 |
| 3 | gopkg.in/yaml.v3 |
29 | 1 |
| 4 | github.com/davecgh/go-spew |
27 | 0 |
| 5 | github.com/stretchr/testify |
27 | 4 |
| 6 | github.com/pmezard/go-difflib |
26 | 0 |
| 7 | google.golang.org/protobuf |
23 | 4 |
| 8 | golang.org/x/net |
22 | 5 |
| 9 | golang.org/x/text |
20 | 4 |
| 10 | github.com/google/go-cmp |
18 | 1 |
| Rank | Module | Out-Degree | In-Degree |
|---|---|---|---|
| 1 | go.etcd.io/etcd/tests/v3 |
88 | 1 |
| 2 | go.etcd.io/etcd/v3 |
83 | 0 |
| 3 | go.etcd.io/etcd/etcdutl/v3 |
70 | 2 |
| 4 | go.etcd.io/etcd/server/v3 |
69 | 3 |
| 5 | go.etcd.io/etcd/etcdctl/v3 |
37 | 2 |
| 6 | go.etcd.io/etcd/client/v3 |
33 | 5 |
| 7 | google.golang.org/grpc |
32 | 17 |
| 8 | github.com/prometheus/common |
26 | 7 |
| 9 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc |
25 | 4 |
| 10 | github.com/grpc-ecosystem/go-grpc-middleware/v2 |
22 | 6 |
Figure 1. Full dependency graph (10 modules):
Figure 2. Core dependency graph (8 modules, excl. tools + tests):
| Metric | Value |
|---|---|
| Total cycles | 13 |
| 2-node cycles | 7 |
| Cycle | Ecosystem |
|---|---|
github.com/golang/protobuf ↔ google.golang.org/protobuf |
Protobuf |
github.com/prometheus/client_golang ↔ github.com/prometheus/common |
Prometheus |
go.opentelemetry.io/auto/sdk ↔ go.opentelemetry.io/otel |
OTel |
go.opentelemetry.io/otel ↔ go.opentelemetry.io/otel/metric |
OTel |
go.opentelemetry.io/otel ↔ go.opentelemetry.io/otel/trace |
OTel |
go.opentelemetry.io/otel/sdk ↔ go.opentelemetry.io/otel/sdk/metric |
OTel |
golang.org/x/crypto ↔ golang.org/x/net |
Go stdlib extended |
| Module | Cycle Count |
|---|---|
go.opentelemetry.io/otel |
7 |
go.opentelemetry.io/auto/sdk |
4 |
go.opentelemetry.io/otel/metric |
4 |
go.opentelemetry.io/otel/trace |
4 |
golang.org/x/net |
3 |
All cycles originate from external ecosystems. No etcd-internal cycles.
8 archived dependencies detected:
| Module | Version | Repository |
|---|---|---|
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 |
json-iterator/go |
v1.1.12 | GitHub |
opentracing/opentracing-go |
v1.1.0 | GitHub |
pkg/errors |
v0.8.1 | GitHub |
golang/lint |
v0.0.0-2019... | GitHub |
Priority replacements:
opentracing-go→ already superseded by OTel (likely transitive only)pkg/errors→ usefmt.Errorfwith%wor stdliberrorsjson-iterator/go→ useencoding/jsonorgo-jsongolang/mock→ usego.uber.org/mock(maintained fork)google/btree→ check if still needed or switch to stdlib generics
| Metric | v3.5.0 | v3.6.0 | Delta |
|---|---|---|---|
| Direct Deps | 51 | 87 | +36 |
| Transitive Deps | 178 | 113 | -65 |
| Total Deps | 192 | 141 | -51 |
| Max Depth | 12 | 12 | ±0 |
Module graph: +41 added, -92 removed, ~70 version changes
- HashiCorp stack removed —
consul,serf,memberlist,hcl,viper, and 15+ related modules - Legacy gRPC ecosystem —
grpc-gatewayv1,go-grpc-prometheus, coreos-era deps (coreos/bbolt,coreos/etcd,coreos/go-systemd,coreos/pkg) - GCP SDK mass removal —
cloud.google.com/go/*(bigquery, datastore, firestore, pubsub, storage) - Deprecated JWT —
dgrijalva/jwt-go,form3tech-oss/jwt-go - Misc cleanup —
shurcooL,smartystreets,mitchellh/*,urfave/cli
- OTel stack —
go.opentelemetry.io/auto/sdk,contrib/detectors/gcp,otel/exporters/otlp/otlptrace/otlptracegrpc - CEL + protovalidate —
github.com/google/cel-go,buf.build/gen/go/bufbuild/protovalidate - Raft extraction —
go.etcd.io/raft/v3(moved to separate module) - Modern gRPC middleware —
go-grpc-middleware/v2,grpc-gateway/v2 - Modern JWT —
golang-jwt/jwt/v5
Figure 3. Diff graph (v3.5.0 → v3.6.0):
Directly depended on by 17 modules (8 etcd modules + 9 external).
Core RPC transport for etcd's client-server communication. Every etcd module from api/v3 through tests/v3 directly depends on gRPC.
Key etcd modules: api/v3, client/v3, etcdctl/v3, etcdutl/v3, pkg/v3, server/v3, tests/v3, v3
Figure 4. Why-trace for gRPC:
Directly depended on by 12 modules (4 etcd modules + 8 OTel/external).
Tracing and metrics across server/client flows. Etcd modules etcdutl/v3, server/v3, tests/v3, v3 directly depend on OTel.
Figure 5. OTel dependency subgraph:
Directly depended on by 4 etcd modules: etcdutl/v3, server/v3, tests/v3, v3.
Embedded B+tree storage engine for etcd's persistence layer. All paths are short (1-2 hops from main modules).
Figure 6. Why-trace for bbolt:
Directly depended on by 7 modules (5 etcd modules + 2 external).
Metrics instrumentation used throughout etcd. Enters the graph via client/v3 and propagates to etcdctl/v3, etcdutl/v3, server/v3, tests/v3, v3.
Figure 7. Why-trace for Prometheus client:
Directly depended on by 9 modules (8 etcd modules + 1 external).
Logging infrastructure rooted in client/pkg/v3 and propagated to nearly every etcd module.
Key etcd modules: client/pkg/v3, client/v3, etcdctl/v3, etcdutl/v3, pkg/v3, server/v3, tests/v3, v3
Figure 8. Why-trace for zap:
- Replace archived dependencies — prioritize
opentracing-go,pkg/errors,json-iterator/go, andgolang/mock(see Section 6). - Monitor OTel cycle complexity — OTel accounts for 7 of 13 cycles. As the OTel ecosystem matures, these may resolve upstream.
- Track tools module separately — the 3 tools modules are excluded from this analysis by design; consider periodic audits to prevent transitive bloat from linters.
- Continue dependency diet — the v3.5→v3.6 reduction of 51 deps was significant. Consider further pruning of indirect GCP/cloud deps that may no longer be needed.
All commands run from the etcd repo root:
# Stats
depstat stats --json
depstat stats --json --exclude-modules "go.etcd.io/etcd/tools/*" --exclude-modules "go.etcd.io/etcd/tests/*"
depstat stats --split-test-only --json
# Graph
depstat graph --svg > etcd-full-graph.svg
depstat graph --svg --exclude-modules "go.etcd.io/etcd/tools/*" --exclude-modules "go.etcd.io/etcd/tests/*" > etcd-core-graph.svg
depstat graph --top both
# Cycles
depstat cycles --summary --json
# Archived
GITHUB_TOKEN=$(gh auth token) depstat archived --json
# Diff
depstat diff v3.5.0 v3.6.0 --verbose
depstat diff v3.5.0 v3.6.0 --svg > etcd-diff-v35-v36.svg
# Why-traces
depstat why google.golang.org/grpc --svg > etcd-why-grpc.svg
depstat graph -p go.opentelemetry.io/otel --svg > etcd-why-otel.svg
depstat why go.etcd.io/bbolt --svg > etcd-why-bbolt.svg
depstat why github.com/prometheus/client_golang --svg --max-paths 50 > etcd-why-client_golang.svg
depstat why go.uber.org/zap --svg > etcd-why-zap.svg