> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goakt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Service Discovery

> Discovery providers for cluster membership.

In clustered mode, nodes must discover each other. GoAkt uses a pluggable **discovery provider** that implements the `discovery.Provider` interface. Pass the provider to `ClusterConfig.WithDiscovery()` when creating the cluster.

## Provider interface

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
package discovery

type Provider interface {
    ID() string
    Initialize() error
    Register() error
    Deregister() error
    DiscoverPeers() ([]string, error)
    Close() error
}
```

| Method            | Purpose                                        |
| ----------------- | ---------------------------------------------- |
| **ID**            | Provider name.                                 |
| **Initialize**    | One-time setup (e.g., connect to backend).     |
| **Register**      | Register this node with the discovery backend. |
| **Deregister**    | Remove this node on shutdown.                  |
| **DiscoverPeers** | Return peer addresses as `host:port` strings.  |
| **Close**         | Release resources.                             |

## Built-in providers

| Provider         | Package                 | Use case                              |
| ---------------- | ----------------------- | ------------------------------------- |
| **Consul**       | `discovery/consul`      | HashiCorp Consul.                     |
| **etcd**         | `discovery/etcd`        | etcd.                                 |
| **Kubernetes**   | `discovery/kubernetes`  | K8s API for pod discovery.            |
| **NATS**         | `discovery/nats`        | NATS for peer discovery.              |
| **mDNS**         | `discovery/mdns`        | Multicast DNS (local networks).       |
| **DNS-SD**       | `discovery/dnssd`       | DNS-based service discovery.          |
| **Static**       | `discovery/static`      | Fixed list of peer addresses.         |
| **Self-managed** | `discovery/selfmanaged` | UDP broadcast on LAN; no peer config. |

Each provider has its own config type. See the package for constructors and options.

### Kubernetes

The Kubernetes provider lists pods through the Kubernetes API, matching the configured labels and `status.phase=Running`. Pods do not need to be Ready to be discovered: on a cold start no pod is Ready until its actor system has joined the cluster, so readiness cannot gate discovery. Terminating pods and pods without an assigned IP are excluded, and an empty result is treated as a retryable error so that simultaneously starting replicas keep retrying until they see each other.

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
import "github.com/tochemey/goakt/v4/discovery/kubernetes"

config := &kubernetes.Config{
    Namespace:         "default",
    DiscoveryPortName: "gossip",
    RemotingPortName:  "remoting",
    PeersPortName:     "cluster",
    PodLabels:         map[string]string{"app": "goakt"},
}
provider := kubernetes.NewDiscovery(config)
```

<Tip>
  For production deployments, set `WithMinimumPeersQuorum` to a majority of the replica count (e.g. 2 for 3 replicas). With the default quorum of 1, a node that cannot reach its peers is allowed to operate as a single-node cluster.
</Tip>

### Self-managed (zero config)

The self-managed provider uses UDP broadcast for peer discovery. No third-party services or peer IPs are required; nodes on the same LAN discover each other automatically.

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
import "github.com/tochemey/goakt/v4/discovery/selfmanaged"

config := selfmanaged.Config{
    ClusterName: "my-app",
    SelfAddress: "192.168.1.10:7946",
}
provider := selfmanaged.NewDiscovery(&config)
```

## Configuration

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
provider, err := consul.New(config)
// or: etcd.New(config), kubernetes.New(config), etc.
clusterConfig := actor.NewClusterConfig().
    WithDiscovery(provider).
    WithKinds(actor1, actor2)

system, _ := actor.NewActorSystem("app",
    actor.WithRemote(remoteConfig),
    actor.WithCluster(clusterConfig),
)
```

The provider is used by the cluster to find peers. Remoting must be enabled (`WithRemote`) for cross-node communication.

## Custom provider

Implement `discovery.Provider` and pass it to `WithDiscovery`. See [Extending GoAkt](/contributing/extending#discovery-provider) for the interface and wiring.
