# Getting Started with Watermill (/integrations/watermill/tutorials/getting-started)



The `watermill-kubemq` plugin implements Watermill's `message.Publisher` and `message.Subscriber` interfaces on top of the KubeMQ broker. This guide installs the plugin, starts a local broker, and runs a complete Events round-trip through the Watermill Router in a few minutes.

## Getting started [#getting-started]

<Steps>
  <Step>
    ### Prerequisites [#prerequisites]

    You need the following installed locally:

    | Requirement | Version                                     |
    | ----------- | ------------------------------------------- |
    | Go          | 1.25+                                       |
    | Docker      | Any recent version (for running the broker) |

    The Go version requirement comes from the plugin's module (`go 1.25.0`); the runnable examples in the repository assume the same toolchain.
  </Step>

  <Step>
    ### Start a KubeMQ Broker [#start-a-kubemq-broker]

    The plugin connects to KubeMQ over gRPC, so you need a broker running on your machine. The fastest way is the `docker-compose.yml` shipped with the repository:

    ```bash
    docker-compose up -d
    ```

    If you prefer to run the container directly without Compose:

    <RunKubeMQ ports="[50000, 8080, 9090]" />

    The broker exposes three ports:

    | Port    | Purpose                            |
    | ------- | ---------------------------------- |
    | `50000` | gRPC API — **used by this plugin** |
    | `8080`  | REST API and health endpoint       |
    | `9090`  | Prometheus metrics                 |

    <Callout type="info">
      Unlike HTTP-based connectors (such as CloudEvents or A2A), there is **no enable flag** to set. The Watermill plugin is a native gRPC client: it dials the broker's gRPC port (`50000`) directly. As long as the broker is up and `50000` is reachable, the plugin can publish and subscribe — nothing else needs to be turned on.
    </Callout>
  </Step>

  <Step>
    ### Install the Plugin [#install-the-plugin]

    Add the module to your project with `go get`:

    ```bash
    go get github.com/kubemq-io/watermill-kubemq
    ```

    This pulls in the plugin along with its dependencies, including Watermill (`github.com/ThreeDotsLabs/watermill`) and the KubeMQ Go SDK (`github.com/kubemq-io/kubemq-go/v2`).
  </Step>

  <Step>
    ### Run Your First End-to-End Example [#run-your-first-end-to-end-example]

    The example below wires a Watermill Router that reads from one Events topic, logs each message, and forwards it to an output topic — then publishes `hello events` into the input topic. Save it as `main.go` and run it with a broker listening on `localhost:50000`.

    ```go title="main.go"
    package main

    import (
        "context"
        "log"

        "github.com/ThreeDotsLabs/watermill"
        "github.com/ThreeDotsLabs/watermill/message"
        "github.com/ThreeDotsLabs/watermill/message/router/middleware"
        kubemq "github.com/kubemq-io/watermill-kubemq/pkg/kubemq"
    )

    func main() {
        logger := watermill.NewStdLogger(false, false)

        pub, err := kubemq.NewPublisher(kubemq.PublisherConfig{
            Address: "localhost:50000",
            Pattern: kubemq.PatternEvents,
            Logger:  logger,
        })
        if err != nil {
            log.Fatal(err)
        }
        defer pub.Close()

        sub, err := kubemq.NewSubscriber(kubemq.SubscriberConfig{
            Address: "localhost:50000",
            Pattern: kubemq.PatternEvents,
            Logger:  logger,
        })
        if err != nil {
            log.Fatal(err)
        }
        defer sub.Close()

        router, err := message.NewRouter(message.RouterConfig{}, logger)
        if err != nil {
            log.Fatal(err)
        }

        router.AddMiddleware(middleware.Recoverer)
        router.AddHandler("events-handler", "my-topic", sub, "output-topic", pub,
            func(msg *message.Message) ([]*message.Message, error) {
                log.Printf("Received: %s", string(msg.Payload))
                return []*message.Message{msg}, nil
            },
        )

        // Publish a message
        go func() {
            msg := message.NewMessage(watermill.NewUUID(), []byte("hello events"))
            if err := pub.Publish("my-topic", msg); err != nil {
                log.Printf("Publish error: %v", err)
            }
        }()

        _ = router.Run(context.Background())
    }
    ```

    Run it from your module:

    ```bash
    go run main.go
    ```

    You should see the router log `Received: hello events` as the message flows through the handler.
  </Step>

  <Step>
    ### Understand the Pieces [#understand-the-pieces]

    A few things are worth calling out in the example above.

    **The imports.** The plugin builds on Watermill's core packages plus the KubeMQ adapter:

    | Import                                                         | Role                                                     |
    | -------------------------------------------------------------- | -------------------------------------------------------- |
    | `github.com/ThreeDotsLabs/watermill`                           | Core helpers — `NewStdLogger`, `NewUUID`                 |
    | `github.com/ThreeDotsLabs/watermill/message`                   | `Message`, `Publisher`/`Subscriber` interfaces, `Router` |
    | `github.com/ThreeDotsLabs/watermill/message/router/middleware` | Standard middleware such as `Recoverer`                  |
    | `github.com/kubemq-io/watermill-kubemq/pkg/kubemq`             | The KubeMQ plugin — imported under the alias `kubemq`    |

    **The pattern.** Both the publisher and subscriber are created with `Pattern: kubemq.PatternEvents`. KubeMQ supports three messaging patterns, and each Publisher/Subscriber instance serves exactly one. `PatternEvents` is the fire-and-forget pattern.

    **The router.** `message.NewRouter` builds a router; `AddMiddleware(middleware.Recoverer)` wraps handlers so a panic is recovered instead of crashing the process; and `AddHandler` wires an input topic + subscriber to an output topic + publisher with a handler function. Returning the message from the handler forwards it to `output-topic`.

    <Callout type="warn">
      Events are **at-most-once** and fire-and-forget. The subscriber must be active **before** you publish, or the message is dropped — there is no persistence and no replay for this pattern. In the example, the router (which establishes the subscription) starts inside `router.Run`, while the publish runs in a goroutine, so the subscription is in place by the time the message is sent. If you need guaranteed delivery, persistence, or replay, use the Queues or EventsStore patterns instead.
    </Callout>
  </Step>

  <Step>
    ### Try the Runnable Examples [#try-the-runnable-examples]

    The repository ships complete, runnable programs for the Events pattern. With a broker running on `localhost:50000`, run them from the project root:

    ```bash
    go run ./examples/events/basic-pubsub/main.go
    ```

    The `basic-pubsub` example uses the direct Publisher/Subscriber API to send and receive three messages on `watermill-events.basic-pubsub`. For the Router-based flow shown above, run:

    ```bash
    go run ./examples/events/router-handler/main.go
    ```

    The `router-handler` example reads from `watermill-events.router-input`, uppercases each payload in the handler, and forwards it to `watermill-events.router-output`.

    <Callout type="info">
      The repository README refers to these programs under an `_examples/` path, but the actual directory in the repo is `examples/`. Use `./examples/...` when running them, as shown above.
    </Callout>
  </Step>

  <Step>
    ### Next Steps [#next-steps]

    <Cards>
      <Card title="Concepts" href="/integrations/watermill/concepts/concepts" description="How the plugin maps Watermill Publishers, Subscribers, and the Router onto KubeMQ's three messaging patterns." />

      <Card title="Queues" href="/integrations/watermill/how-to/queues" description="Reliable, at-least-once delivery with explicit ack/nack, competing consumers, and dead-letter queues." />

      <Card title="Reference" href="/integrations/watermill/reference/configuration" description="Full PublisherConfig, SubscriberConfig, and configuration field reference." />
    </Cards>
  </Step>
</Steps>
