etcd-client

The asynchronous Rust client for etcd's v3 API, built on tokio and tonic.

SDK
Cargo
v0.20.0
262stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
75/100Good
Development Activity76
Maintenance76
Community68
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture82
Code Quality78
Innovation75
Learning Curve65

etcd-client is the de facto Rust client library for etcd, the distributed, consistent key-value store that backs Kubernetes and countless other distributed systems. Built on tokio for async I/O and tonic for gRPC transport, it wraps etcd’s full v3 API surface — key-value operations, watch streams, leases, distributed locks, leader election, authentication, cluster membership, and maintenance — behind a single async Client handle that can be cloned cheaply across tasks.

The crate favors precise, typed error handling over generic failures, and offers pluggable transport security (rustls or OpenSSL) via Cargo feature flags, letting consumers opt into exactly the TLS stack and API surface they need without paying for the rest.

What You Get

  • A single async Client exposing eight sub-clients (KV, Watch, Lease, Lock, Auth, Maintenance, Cluster, Election) covering etcd’s entire v3 API surface.
  • Cargo feature flags for rustls or OpenSSL TLS, native/webpki trust roots, and an opt-in raw-channel escape hatch for custom transport construction.
  • Namespaced KvClientPrefix/LeaseClientPrefix wrappers for multi-tenant key prefixing without re-implementing prefix logic yourself.
  • Runnable examples for every sub-client (kv, watch, lease, lock, election, maintenance, cluster, auth_role, auth_user) under examples/.

Common Use Cases

  • Kubernetes-adjacent tooling — Rust operators, controllers, and CLIs that read or write the same etcd cluster Kubernetes uses for state.
  • Distributed configuration and service discovery — services store and watch shared config or registered endpoints and react to change events via WatchClient.
  • Leader election for singleton workloads — a fleet of replica processes campaigns for and holds a lease-backed leadership token via ElectionClient.
  • Distributed locking around critical sections — services coordinate mutually exclusive access to a shared resource using LockClient’s lease-backed locks.
  • TTL-based resource cleanup — short-lived resources are tied to etcd leases so they’re automatically revoked if a client stops renewing.

Under The Hood

Architecture The Client struct in src/client.rs holds eight sub-clients (kv, watch, lease, lock, auth, maintenance, cluster, election) plus ConnectOptions, a channel-change sender, and a ClientCaller. Client::connect builds a balanced channel (tonic’s native channel by default, or an OpenSSL-backed one behind the tls-openssl feature) through the BalancedChannelBuilder trait, then constructs every sub-client from that shared channel in connect_with_balanced_channel. Each file under src/rpc/ (auth.rs, cluster.rs, election.rs, kv.rs, lease.rs, lock.rs, maintenance.rs, watch.rs) wraps one generated tonic-prost gRPC service in a typed request/response API, converting protobuf types into public equivalents. src/caller.rs centralizes per-call options and the auth-token interceptor implemented in src/intercept.rs; src/channel.rs abstracts channel construction so callers can swap the default tonic channel for an OpenSSL-backed one (src/openssl_tls/) without touching client.rs. The layering runs transport (channel/intercept) -> generated protobuf (rpc/pb.rs, produced by build.rs via tonic-prost-build) -> typed RPC wrappers (rpc/*.rs) -> facade (client.rs) -> public re-exports (lib.rs); changing the core Client struct ripples into every sub-client constructor since they’re all assembled together in one function.

Tech Stack Rust 2021 edition, MSRV 1.80. gRPC transport runs on tonic 0.14 and tonic-prost 0.14, with protobuf codegen via prost 0.14 and a build.rs that runs tonic-build/tonic-prost-build against etcd’s vendored .proto files under proto/. The crate is runtime-agnostic in principle but its dev-dependencies pull tokio’s “full” feature for tests and examples. TLS is pluggable: rustls (tls-ring/tls-aws-lc features) via tonic’s built-in rustls integration, or OpenSSL (tls-openssl/tls-openssl-vendored) via a hand-rolled hyper + hyper-openssl + hyper-util connector in src/openssl_tls/. tower/tower-service supply the Service abstraction tonic channels implement. There’s no ORM or database layer beyond the etcd gRPC wire protocol itself, and no CLI; the test-only serial_test dependency forces integration tests that share cluster state to run sequentially.

Code Quality tests/client.rs is a substantial integration suite (roughly 23KB) exercising KV, Watch, Lease, Lock, Auth, Cluster, Election, and Maintenance end-to-end against a real etcd server spun up in CI via Docker, with serial_test serializing tests that share cluster state; tests/namespace.rs and tests/testing.rs cover the prefixed-client wrappers. There are no unit tests inside src/ itself — correctness is validated exclusively through this live-etcd integration suite. Error handling is explicit and typed through a single Error enum (src/error.rs) with From impls for every underlying error source (transport, gRPC status, UTF-8, invalid URI/metadata, OpenSSL) rather than boxed or opaque errors. CI runs cargo fmt --check and clippy across the full Cargo feature powerset via cargo-hack (excluding mutually exclusive TLS feature combinations) with -D warnings, an unusually rigorous cross-feature lint matrix for a crate this size. Naming is consistent throughout rpc/*.rs, following an XxxOptions/XxxResponse pattern for every RPC.

API Design The single-Client-with-sub-clients pattern gives a low-boilerplate entry point — Client::connect(["localhost:2379"], None).await? plus a handful of chained calls is enough to get started, matching the README’s own quickstart. Options structs (PutOptions, GetOptions, WatchOptions, and others) follow a consistent builder pattern instead of long positional argument lists, and response types expose typed accessors (resp.kvs(), kv.key_str()) rather than raw protobuf bytes. The feature-gated pub-response-field module deliberately punches a hole through the typed façade for advanced users who need underlying protobuf types (for mocking, for example), which reads as a thoughtful escape hatch rather than an all-or-nothing abstraction. Rustdoc comments are present throughout rpc/*.rs, and docs.rs metadata pre-selects the tls/tls-roots feature set so generated docs surface TLS-related APIs by default — though the several mutually exclusive TLS features documented in lib.rs require reading fairly closely to pick the right one.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search