Skip to content
SeeItFlow
Interactive guide · 8 chapters · ~30 min read

etcd Fundamentals

etcd is the distributed key-value store that powers Kubernetes and the coordination layer of most cloud-native infrastructure. This guide builds your understanding from first principles — why etcd exists, what it actually guarantees, and how every feature maps to a real engineering problem.

Mangesh MandlikLast updated:
01 · Foundations

What is etcd?

etcd is a strongly consistent, distributed key-value store designed for reliability, not throughput. It stores small, critical coordination data with well-defined consistency guarantees rather than best-effort behavior.

The name is a portmanteau: /etc (the Unix directory for system configuration) and d (for distributed). That naming choice tells you exactly what etcd was designed for — it's the configuration and coordination backbone of a distributed system, just as /etc is the configuration directory of a single Linux machine.

etcd was created by CoreOS in 2013 to solve a specific problem: when running a cluster of machines, services need a reliable source of truth. Which node is the current leader? What's the current database connection string? Which feature flags are enabled? Storing this in application memory leads to drift. Storing it in a traditional database introduces a new single point of failure. etcd is built to be that store — highly available, strongly consistent, and operationally simple.

Swipe to pan
ClientgRPCetcd-1LEADERetcd-2FOLLOWERetcd-3FOLLOWERKV StorereplicatedAll writes go through the leader → replicated to followers via Raft
The complete etcd round-trip: client writes to leader → leader replicates to followers via Raft → write committed at majority → state visible in KV store.

The guarantees that matter

Strong consistency

Linearizable reads return the latest committed value regardless of which member serves the request, routed through quorum. Serializable reads skip that round-trip and may lag behind the latest write. Choose the mode deliberately — it's a real trade-off between freshness and latency/availability, not a mode you can ignore.

High availability

A 3-node etcd cluster tolerates 1 node failure. A 5-node cluster tolerates 2. As long as a quorum survives, the cluster continues operating. Writes pause during a leader election; how long that takes depends on the configured heartbeat interval and election timeout plus actual network/disk conditions, not a fixed universal number.

Durability

etcd persists every committed write to disk using a WAL (write-ahead log) and replicates it to a quorum before acknowledging the client. Completed writes are durable under etcd's documented guarantees; recovering from an older backup snapshot after a disaster naturally loses anything written after that snapshot.

Atomic operations

etcd supports compare-and-swap transactions: conditional puts that succeed only if a precondition holds. This makes it safe to implement distributed locks, leader election, and config versioning without race conditions.

Interactive

Visual Learning

Watch one etcd cluster handle key-value writes, the Watch API, leases, transactions, Raft leader election, failover, and network partitions as a single continuous system — not twelve separate explanations.

02 · History

Why etcd Exists

Before etcd, every distributed system solved the same coordination problems differently and badly. etcd came from the pain of running real clusters at scale.

The configuration drift problem

Imagine 50 microservices, each holding its own copy of the database host, port, and feature flags. When you need to rotate the database host, you have to restart 50 services in the right order, cross your fingers, and hope they all pick up the change before any user hits an inconsistent service. In practice, some services get the old config, some get the new config, and debugging why half your checkout flow behaves differently from the other half costs you hours of on-call time.

etcd solves this with a single source of truth. Every service reads config from etcd on startup and watches for changes via the Watch API. When the database host rotates, you write one key and every watching service is notified quickly, without polling. The config can't drift because there's only one copy.

The leader election problem

Another classic distributed systems problem: you have five scheduler instances, but only one should execute the daily billing job. How do they agree on which one wins? Without a coordination service, you end up implementing your own mutex over a database row — which doesn't handle the case where the winning instance crashes mid-job and holds the row lock forever. etcd's leases handle this: the winning instance holds a key backed by a TTL lease, and if it crashes, the lease expires and the next instance can win. The lock auto-heals.

03 · The system

etcd Architecture

An etcd cluster is a group of member nodes running the same binary, coordinating via Raft to maintain a replicated key-value store with a single, well-defined history of writes.

Every member runs the same Go binary. There are no separate master and worker roles — each member is capable of being the leader, and leadership rotates via election when the current leader fails. The cluster presents a single logical view: for linearizable reads and all writes, clients get a result consistent with every write acknowledged before it, regardless of which member they contact, because every committed write has been replicated to a quorum before the leader acknowledged it.

The WAL and snapshots

etcd persists state in two forms: the write-ahead log (WAL) and periodic snapshots. The WAL records every operation in order — it's the source of truth for recovery. On restart, etcd replays the WAL from the most recent snapshot forward. Snapshots compact the log to avoid unbounded disk growth. The combination of WAL + snapshots gives etcd its durability guarantees without requiring synchronous disk flushes on every read.

The gRPC API

etcd exposes its entire API over gRPC with protobuf serialization. The API surface is intentionally small: KV (Put, Get, Delete, Txn), Lease (Grant, Revoke, KeepAlive, TimeToLive), Watch (Watch), Cluster (MemberList, MemberAdd), and Maintenance (Defragment, Snapshot, AlarmList). Every call is synchronous: a write returns only after it is committed to the Raft log and applied to the state machine, and reads are linearizable by default, so they also go through Raft consensus (serializable reads can be served by a single member and may be stale).

04 · Core API

Key-Value Operations

The etcd KV API is small but deep. Understanding revisions, MVCC, and prefix queries unlocks the full power of the store.

Revisions and MVCC

Every write to etcd advances a cluster-wide revision counter. The revision is a monotonically increasing integer that represents the cluster's history. When you put a key at revision 42, the key exists at revisions 42 and above (until it's deleted or overwritten). This is multi-version concurrency control (MVCC): etcd maintains previous versions of keys until compaction removes them. Clients can fetch the value of any key at any past revision with Get(key, WithRev(n)).

Create revision (CreateRevision)

The cluster revision when the key was first created. Remains constant through all updates. Resets to 0 after deletion and re-creation.

Modification revision (ModRevision)

The cluster revision at which the key was last modified (put or deleted). Advances every time the key changes.

Version

The per-key version counter — how many times this key has been modified since creation. Starts at 1 on creation, increments on each put, resets to 0 on deletion. Distinct from the cluster revision.

Prefix queries

etcd supports range queries over sorted keys. Since keys are lexicographically ordered, all keys under /services/ can be fetched with a single Get call: Get('/services/', WithPrefix()). This is how Kubernetes fetches all Pods in a namespace in one call — it reads /registry/pods/my-namespace/ with prefix. The range query is O(n) in the number of matching keys, backed by bbolt (BoltDB) for fast sorted reads.

05 · Watch

The Watch API

The Watch API is etcd's change-notification mechanism — it tells clients what changed in the key space without polling. It's not a general-purpose event bus: it notifies on etcd state changes, not on arbitrary application events the way Kafka or a message queue would.

A Watch subscribes to changes on a key or prefix starting from a given revision. When a matching key changes, etcd pushes a WatchEvent to every watcher: the event type (PUT or DELETE), the new and old key-value pairs, and the revision. Within a single watch stream, events arrive ordered by revision.

Swipe to pan
Writerputs /k=vWatcherwatching /ketcd clustercommits writePUT /k=vWatchEvent PUT /k=v rev=NKV Storerev=NWatch events are pushed after commit — ordered by revision, never dropped
Write arrives → leader commits → WatchEvent pushed to all subscribers on the matching prefix, ordered by revision.

A watcher can specify a start revision: Watch(key, WithRev(42)) receives events from revision 42 forward, as long as that history hasn't been compacted away. This makes reconnect-and-resume straightforward: save the last processed revision, and on reconnect start the watch from there. But the guarantee has a boundary — if the requested revision has already been compacted, the watch fails and the client must re-list current state instead of replaying from an arbitrarily old point. Consumers should also treat their own processing as idempotent, since retries and reconnects on the client side can replay an event the application already handled.

06 · Leases

Leases and TTLs

Leases are etcd's mechanism for ephemeral ownership. A key attached to a lease lives and dies with that lease — automatically.

A lease is a time-bounded token issued by etcd. The client that holds a lease must send periodic KeepAlive RPCs (heartbeats) to renew it. If the keepalives stop — because the client crashed, the network was severed, or the process was killed — the lease expires after its TTL. When a lease expires, etcd atomically deletes every key attached to it and pushes DELETE WatchEvents to any watchers of those keys.

The practical consequence is powerful: service health, session management, and distributed lock timeouts all reduce to lease TTLs. A service that wants to signal liveness attaches a health key to a lease and heartbeats. A client that crashes stops heartbeating, the lease expires in TTL seconds, and the health key disappears. No human intervention, no cleanup daemons, no stale registrations.

Lease keep-alive

gRPC bidirectional stream — the client sends KeepAlive requests and receives renewed TTL values. The stream should be held open for the lifetime of the application; reconnecting resets the stream but the lease continues as long as a new KeepAlive arrives before expiry.

Lease revoke

A client can explicitly revoke its lease before expiry — useful for clean shutdown. Revocation is immediate: all attached keys are deleted in a single atomic commit.

07 · Transactions

Transactions and Compare-and-Swap

etcd transactions are atomic conditional writes — the coordination primitive that makes distributed locks, leader election, and safe config updates possible.

An etcd transaction (Txn) has three parts: a compare block (the conditions), a success block (operations to run if all conditions pass), and a failure block (operations to run if any condition fails). The entire transaction is applied atomically at a single revision — there's no possibility of interleaving between the compare and the write.

The compare block can test: the current value of a key, its create revision, its mod revision, or its version. The most common pattern is compare-and-swap: 'put this key if and only if its current value equals X'. This is optimistic locking over key-value pairs.

08 · Decision

When to Use etcd

etcd is exceptional for coordination. It is a poor choice for everything else. Knowing the distinction is what separates a good architecture from an over-engineered one.

etcd is the right tool for

Service discovery

Services register their addresses with leases. Consumers watch for changes. A held lease proves the client is maintaining its registration — pair it with real liveness/readiness checks if application health is more than 'process is reachable.'

Leader election

Multiple instances compete for a lock key. The winner heartbeats to hold it. If the leader crashes, the lock expires and another instance wins. Automatic failover.

Distributed configuration

Single source of truth for config shared across services. Atomic updates via transactions. Watch notifications so services react instantly to changes.

Distributed locks

CAS-based lock acquisition with lease-backed auto-release. Prevents two clients from holding the lock key at once — but a paused holder whose lease expires can still resume and act after another client has taken over, so protecting the actual external action (fencing tokens, idempotency) is still the caller's job.

Cluster membership

Track which nodes are alive, what their roles are, and what endpoints they expose. etcd maintains this state with lease-based failure detection.

etcd is the wrong tool for

etcd is not a general-purpose database. It's optimized for small, infrequently-written coordination data rather than high-volume application data. The default storage quota is 2 GiB, and official guidance suggests 8 GiB as a reasonable upper bound for normal environments — etcd warns at startup if you configure something larger. Using etcd to store large blobs, analytics data, user records, or high-volume event streams works against its design and operational model.

Key takeaways
  1. 01Linearizable reads (the default) go through Raft; serializable reads can be served by any member and may be stale — choose per call, not globally.
  2. 02Every mutating operation advances a cluster-wide revision; the per-key version is a different counter. Watch resumes from a revision, but only as far back as compaction allows.
  3. 03A lease-backed key gives automatic cleanup, but a paused lease holder can still act after expiry — protect the external action with fencing tokens or idempotency.
  4. 04Txn compare-and-swap (compare on value, create/mod revision or version) is the primitive behind locks, leader election and config versioning.
  5. 05etcd is for small, rarely-written coordination data: the default quota is 2 GiB and the suggested ceiling is 8 GiB, so keep application data elsewhere.