---
title: Discovery
description: Service discovery and registry with multiple backends and FARP integration
---

## Overview

`github.com/xraph/forge/extensions/discovery` provides service discovery and registration for
Forge applications. It registers a `Service` in the DI container that manages service instances
across pluggable backends (memory, Consul, etcd, mDNS) and optionally exposes FARP endpoints
for schema-based API discovery.

## What It Registers

| Service | DI Key | Type |
|---|---|---|
| Discovery service | `discovery` | `*Service` |

The service is registered with Vessel and supports the legacy alias `discovery.Service`.

## Quick Start

```go
package main

import (
    "context"
    "fmt"

    "github.com/xraph/forge"
    "github.com/xraph/forge/extensions/discovery"
)

func main() {
    app := forge.NewApp(forge.AppConfig{Name: "user-service", Version: "1.0.0"})

    app.RegisterExtension(discovery.NewExtension(
        discovery.WithEnabled(true),
        discovery.WithBackend("consul"),
        discovery.WithService(discovery.ServiceConfig{
            Name:    "user-service",
            Version: "1.0.0",
            Port:    8080,
            Tags:    []string{"api", "v1"},
            Metadata: map[string]string{"team": "platform"},
        }),
        discovery.WithConsul(discovery.ConsulConfig{
            Address: "localhost:8500",
        }),
    ))

    ctx := context.Background()
    app.Start(ctx)  // auto-registers with Consul
    defer app.Stop(ctx)  // auto-deregisters

    svc, _ := forge.InjectType[*discovery.Service](app.Container())

    // Discover other services
    instances, _ := svc.Discover(ctx, "order-service")
    for _, inst := range instances {
        fmt.Printf("Found: %s at %s\n", inst.ID, inst.URL("http"))
    }

    // Discover healthy instances only
    healthy, _ := svc.DiscoverHealthy(ctx, "order-service")

    // Select one with load balancing
    selected, _ := svc.SelectInstance(ctx, "order-service", "round-robin")
    fmt.Printf("Selected: %s\n", selected.URL("http"))

    // Watch for changes
    svc.Watch(ctx, "order-service", func(instances []discovery.ServiceInstance) {
        fmt.Printf("Service updated: %d instances\n", len(instances))
    })
}
```

## FARP Integration

FARP (Forge API Registration Protocol) lets your service publish API schema metadata so the gateway
can automatically discover and proxy traffic to it. When FARP is enabled, the extension registers
two HTTP endpoints (`/_farp/manifest` and `/_farp/discovery`) and injects FARP metadata into the
service's discovery registration (mDNS TXT records, Consul metadata, etcd keys, etc.).

```go
discovery.NewExtension(
    discovery.WithEnabled(true),
    discovery.WithBackend("mdns"),
    discovery.WithServiceName("user-service"),
    discovery.WithFARPEnabled(true),
    discovery.WithFARPAutoRegister(true),
    discovery.WithFARPEndpoints(discovery.FARPEndpointsConfig{
        OpenAPI: "/openapi.json",
    }),
)
// Exposes: GET /_farp/manifest and GET /_farp/discovery
// mDNS TXT records now include farp.enabled=true, farp.manifest=..., farp.openapi=...
```

### FARP with mDNS (Zero-Config Local Development)

The most common local-development setup uses mDNS with FARP. No external infrastructure is needed --
services and gateways discover each other over the local network automatically:

```go
package main

import (
    "context"

    "github.com/xraph/forge"
    "github.com/xraph/forge/extensions/discovery"
)

func main() {
    app := forge.NewApp(forge.AppConfig{Name: "order-service", Version: "1.0.0"})

    app.RegisterExtension(discovery.NewExtension(
        discovery.WithEnabled(true),
        discovery.WithBackend("mdns"),
        discovery.WithServiceName("order-service"),

        // Enable FARP so the gateway can auto-discover this service.
        discovery.WithFARPEnabled(true),
        discovery.WithFARPAutoRegister(true),
        discovery.WithFARPEndpoints(discovery.FARPEndpointsConfig{
            OpenAPI: "/openapi.json",
            Health:  "/health",
        }),
        discovery.WithFARPCapabilities("http", "rest"),
    ))

    ctx := context.Background()
    app.Start(ctx)
    defer app.Stop(ctx)
}
```

When this service starts it:
1. Registers itself via mDNS on the local network (service type `_order-service._tcp`).
2. Includes FARP metadata in mDNS TXT records (`farp.enabled=true`, `farp.manifest=http://.../_farp/manifest`, `farp.openapi=http://.../openapi.json`).
3. Exposes `GET /_farp/manifest` returning the service's API schema manifest.
4. The gateway extension on another Forge app discovers this service, reads the manifest, and auto-generates proxy routes.

### FARP with Consul (Production)

For production deployments, use Consul as the backend. FARP metadata is stored in Consul service metadata:

```go
discovery.NewExtension(
    discovery.WithEnabled(true),
    discovery.WithConsul("consul.internal:8500", ""),
    discovery.WithServiceName("payment-service"),
    discovery.WithServiceTags("api", "v2"),
    discovery.WithFARPEnabled(true),
    discovery.WithFARPAutoRegister(true),
    discovery.WithFARPSchemas(
        discovery.FARPSchemaConfig{
            Type:        "openapi",
            SpecVersion: "3.1",
            Location: discovery.FARPLocationConfig{
                Type: "url",
                URL:  "/openapi.json",
            },
            ContentType: "application/json",
        },
    ),
    discovery.WithFARPEndpoints(discovery.FARPEndpointsConfig{
        Health:  "/health",
        Metrics: "/metrics",
        OpenAPI: "/openapi.json",
    }),
    discovery.WithFARPCapabilities("http", "rest", "webhooks"),
)
```

## Key Concepts

- **Backends** -- choose between `memory` (default), `consul`, `etcd`, `mdns`, `kubernetes`, or `eureka`.
- **Service registration** -- register the current service with the backend on startup.
- **Service discovery** -- discover healthy instances by name or tags with load balancing.
- **Health checks** -- periodic checks with configurable interval and timeout.
- **Watching** -- watch for service changes in real-time.
- **FARP** -- expose `/_farp/manifest` and `/_farp/discovery` for API schema-based discovery.
- **mDNS + FARP** -- zero-config local development where FARP metadata is carried in mDNS TXT records.

## Important Runtime Notes

- The `memory` backend is local-only and does not share state across nodes.
- Consul and etcd backends require running infrastructure.
- FARP endpoints enable the gateway extension to auto-discover and proxy routes.
- When using mDNS, the service name determines the mDNS service type (`_<name>._tcp`). Use `WithServiceName` or `WithMDNSServiceType` to control it.

## Detailed Pages

<Cards>
<Card title="Features" href="/docs/forge/extensions/discovery/features">
Backends, FARP, health checks, and watching capabilities.
</Card>
<Card title="Configuration" href="/docs/forge/extensions/discovery/configuration">
Config reference, YAML example, and programmatic options.
</Card>
<Card title="Functions" href="/docs/forge/extensions/discovery/functions">
Public API grouped by purpose with descriptions.
</Card>
</Cards>
