# hashicorp/serf: gossip membership with no coordinator to lose

> A Go library and agent that spreads node membership, failure detection and events through gossip. Strong on discovery, deliberately silent on agreement.

**hashicorp/serf** — Service orchestration and management tool.

- Repository: https://github.com/hashicorp/serf
- Website: https://github.com/hashicorp/serf/blob/master/docs/index.html.markdown
- Stars: 6,074 · Forks: 608
- Language: Go
- License: MPL-2.0
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/hashicorp-serf

## Membership, failure detection and no coordinator

The README calls Serf a decentralized solution for service discovery and orchestration. Everything after that follows from the architecture: each node runs an agent, every agent gossips with a handful of neighbours, and the cluster converges on a shared membership list with nothing coordinating it. The README states plainly that Serf is completely masterless with no single point of failure, and that it runs on Linux, Mac OS X and Windows.

What Serf does not do is store anything. There is no replicated log, no leader election and no linearizable read, which is exactly where hashicorp/raft draws the opposite line. Serf tells you which nodes are alive and pushes events. It does not tell you that a write was committed on a majority. If your question is who is up, gossip answers it well. If your question is whether this write is durable everywhere, Serf is the wrong library and a consensus implementation is the right one.

The README's use cases cluster into three shapes: registering web servers with a load balancer, grouping memcached or redis nodes into a pool that something like twemproxy sits in front of, and propagating change, whether deploy triggers, configuration updates or DNS record edits.

## Running two agents and joining them over loopback

The quick start takes three commands and two terminals. The first agent binds a gossip port and a separate RPC port on loopback:

```bash
serf agent -node=foo -bind=127.0.0.1:5000 -rpc-addr=127.0.0.1:7373
```

The second agent needs its own pair of ports, and the README asks for a separate terminal so you can watch both:

```bash
serf agent -node=bar -bind=127.0.0.1:5001 -rpc-addr=127.0.0.1:7374
```

At that point the two agents know nothing about each other. A node joins an existing cluster by naming at least one member, after which gossip carries the news:

```bash
serf join 127.0.0.1:5001
```

Membership is then readable through the CLI, which is the fastest way to confirm the join took effect:

```bash
serf members
```

The output pairs each node name with its address and a state, and both show as alive once the join has propagated. Worth noticing that joining here is one message: the agent you name is unaware of the joiner until the next gossip round, which is why the README describes the agents as becoming aware of each other rather than synchronised.

## A library with an agent attached, and where the docs moved

Serf describes itself as a library first with a command line interface attached. The agent lives under `cmd/serf`, and the README is explicit that applications embedding Serf should depend only on `github.com/hashicorp/serf` rather than on the agent. That split is visible in the tree: `coordinate/` holds coordination state, `client/` the RPC client used to talk to an agent, `dist/` the packaging, `scripts/` and `version/` the release tooling, and `testutil/` the helpers the project's own tests lean on.

Getting the binary is the easy part. The README offers a pre-built release for your operating system, a standalone go get of the command, or compiling from source:

```bash
go get -u github.com/hashicorp/serf/cmd/serf
```

One wrinkle for anyone arriving from an old link: the Serf website was shut down on 2024-10-02, and the README now redirects to documentation checked into the repository, with the homepage pointing at `docs/index.html.markdown`. That matters more than it sounds, because the hosted site is where the agent reference, the event docs and the query interface were published. Everything now lives under `docs/`, and the chat and mailing list moved to Gitter and Google Groups.

The tree also carries two runnable demos under `demo/`: `demo/vagrant-cluster/` and `demo/web-load-balancer/`. The second one is the faster one to read, because a load balancer driven by membership is the use case the README leads with.

## Graceful leave against force kill, and what it costs you

The README's account of a dying agent is the most useful paragraph in the file, because it draws the line between graceful and abrupt failure. Interrupt an agent with ctrl-C and it leaves gracefully by telling the cluster it intends to, so membership updates right away. Force kill an agent and detection falls to another member, which the README says usually happens within seconds. Either way both agents update their lists.

The gap between those two sentences is the entire consistency model. Graceful leave is an explicit message and takes effect at once. Abrupt failure is inferred from gossip timeout, so it is eventually consistent by construction, and its timing depends on suspicion and timeout settings rather than on anything a client can wait on.

That is a good trade for membership, where the useful behaviour is stop sending traffic to this address, and a poor one for coordination. Two nodes can disagree about who is present for a window of seconds, so anything built on Serf membership has to tolerate a stale view. When you need agreement rather than eventual knowledge, that is the line between Serf and a consensus library, and no configuration flag moves it.

## Metrics build tags, memberlist and the 2026 releases

The busiest area of Serf's recent history is metrics plumbing, and the release notes describe a deprecation that took two steps. The library can emit through either `github.com/armon/go-metrics` or `github.com/hashicorp/go-metrics`, chosen by build tags: `armonmetrics` routes to the old package, `hashicorpmetrics` routes to the new one, and with no tag at all the default was still armon. The README marks the armon path deprecated, with the default expected to flip in mid-2025 and opt-in support ending at the end of 2025.

The releases are more abrupt than that plan. v0.10.4 on 2026-07-08 fixed a data race during shutdown and updated memberlist, citing HCSEC-2026-18, a memberlist vulnerability to denial of service via a gossip message. The same release moved go-metrics to 0.6.0 and said it now requires the `hashicorpmetrics` build tag. Then v0.11.0 on 2026-09-16 removed the compatibility shim altogether, so no build tags are needed, made member pruning asynchronous, and fixed a bug where message field payloads were not properly bounds-checked. Between those two versions the documented migration changed from add a tag to delete the shim.

Earlier, v0.10.2 on 2025-01-14 fixed a division by zero, improved mDNS handling and shut down the website. The current go.mod declares go 1.26.0 and pins memberlist and go-metrics at v0.7.0. If you pin an older Serf, the build tag requirement in the release notes is the first thing to check, not the API surface.

## A static alpine image, and the limits of gossip

The Dockerfile states the runtime target more clearly than the README does. It builds in a golang:1.26 stage with CGO disabled so the output is a static binary, runs `make pkg/linux_amd64/serf`, then copies that one executable into an alpine:3.24 image whose entrypoint is `/bin/serf`. A ten-line image for an agent that tends to run on every host in a cluster is a reasonable ratio.

From a checkout the route is `make`, which the README says produces `bin/serf` and also places a copy in `$GOPATH/bin/`. The makefile is named `GNUmakefile`, tests run with `make test`, `make format` applies Go formatting, and the `.release/` directory is where packaged artifacts come from. The build assumes Go is installed with a stable version and a GOPATH set up, which dates the instructions even though go.mod itself targets a current toolchain.

The limits are mostly consequences of the design rather than defects. Membership is eventually consistent, so nothing built on it can assume a fresh view. The event system carries no ordering or exactly-once guarantee, so a handler that triggers a deploy has to be safe to run twice. And Serf stores no data, so it cannot tell you which version of a binary is running where; the event system does that only if your handler makes it. Serf is also easy to reach only through a wrapper, which means the CLI documentation is written for exploration while the real interface is the Go package.

## Conclusion

Serf fits when the question is which nodes exist and whether they still answer, and does not fit when a decision has to be agreed rather than eventually observed. Its honest strengths are a single static binary, no coordinator and membership that converges in seconds with no configuration. The same property seen from the other side is the sharp edge: a force killed member is noticed by timeout, so anything acting on membership has to tolerate a stale view and anything listening for events has to be idempotent. Before adopting it, read the agent reference under `docs/`, and check the build tag requirement in the release notes for the version you pin, because that changed twice in 2026. The last push was on 2026-09-16.

## FAQ

### What exactly is a serf?

In HashiCorp's Serf, a decentralized library and agent for service discovery and orchestration. Nodes exchange membership over gossip, detect each other's failures, and can propagate events such as deploys or configuration changes. It keeps no data and reaches no agreement, which is the line between it and a consensus library.

### What is a serf agent and what does it do?

The agent is the long-running process that performs Serf's communication and maintenance work, and it runs until it is told to quit. In a real deployment each node runs one or more agents, more than one only when several cluster types are in play, such as web servers alongside memcached servers. The agent binary sits under cmd/serf and is separate from the library you embed.

### How do I install Serf and build it from source?

The README gives three routes: download a pre-built Serf binary for your operating system, install the command with go get, or compile the repository. From a checkout you need Go with GOPATH set up, clone into $GOPATH/src/github.com/hashicorp/serf, and run make, which produces bin/serf and a copy under $GOPATH/bin. make test runs the tests and make format applies Go formatting.

## Sources

- [hashicorp/serf on GitHub](https://github.com/hashicorp/serf)
- [License: MPL-2.0](https://github.com/hashicorp/serf/blob/master/LICENSE)
- [Project website](https://github.com/hashicorp/serf/blob/master/docs/index.html.markdown)
- [README](https://github.com/hashicorp/serf/blob/master/README.md)
- [Releases](https://github.com/hashicorp/serf/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hashicorp-serf
