# pulsar-client-go: a pure Go client for Apache Pulsar without the C++ library

> The Apache Pulsar Go client library is a pure Go implementation that does not link the C++ Pulsar library, and it is intended to supersede the older CGo-based client once feature parity and stability are reached. It exposes producers, subscriptions and readers over the same broker API, and it is still tracking that parity work rather than declaring it finished.

**apache/pulsar-client-go** — Apache Pulsar Go Client Library

- Repository: https://github.com/apache/pulsar-client-go
- Website: https://pulsar.apache.org/
- Stars: 744 · Forks: 392
- Language: Go
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/apache-pulsar-client-go

## Pure Go means no cgo bridge in your build

The library is described as a pure Go client library for Pulsar that does not depend on the C++ Pulsar library. That single design decision shapes everything else about it, because a cgo dependency means a C++ toolchain in the build image, a cross-compilation matrix to maintain, and a runtime that can fail in ways a pure Go binary cannot.

The stated purpose is explicit about the trajectory. Once feature parity and stability are reached, the library will supersede the current CGo-based library. That is a plan, not a completed migration, and the documentation points to the project's GitHub Projects page for tracking the status and the progress.

The requirement is Go 1.24 or newer, which is worth checking against your existing services before you plan an upgrade. The module file in the repository declares go 1.25.0 as its module directive, while the stated requirement in the readme is Go 1.24+, so the library is usable on 1.24 even though the module metadata names a later version.

The licence is Apache 2.0, with the standard ASF header in every source file and the licence text and NOTICE file at the repository root. There is no contributor gating and no separate commercial edition, which is the usual ASF arrangement.

## Three ways to read a topic: subscribe, or replay from a position

The library offers the three consumption shapes Pulsar itself defines, and the difference between them is a cursor semantics question rather than an API style question.

A producer publishes to a topic. The minimal producer is short:

```go
client, err := pulsar.NewClient(pulsar.ClientOptions{
    URL: "pulsar://localhost:6650",
})

defer client.Close()

producer, err := client.CreateProducer(pulsar.ProducerOptions{
	Topic: "my-topic",
})

_, err = producer.Send(context.Background(), &pulsar.ProducerMessage{
	Payload: []byte("hello"),
})

defer producer.Close()

if err != nil {
    fmt.Println("Failed to publish message", err)
} else {
    fmt.Println("Published message")
}
```

A consumer subscribes with a subscription name and a subscription type, and receives one message at a time:

```go
consumer, err := client.Subscribe(pulsar.ConsumerOptions{
        Topic:            "my-topic",
        SubscriptionName: "my-sub",
        Type:             pulsar.Shared,
    })

defer consumer.Close()

msg, err := consumer.Receive(context.Background())
    if err != nil {
        log.Fatal(err)
    }

fmt.Printf("Received message msgId: %#v -- content: '%s'\n",
            msg.ID(), string(msg.Payload()))
```

A reader instead names a starting position and walks forward without a subscription:

```go
reader, err := client.CreateReader(pulsar.ReaderOptions{
	Topic:          "topic-1",
	StartMessageID: pulsar.EarliestMessageID(),
})
if err != nil {
	log.Fatal(err)
}
defer reader.Close()

for reader.HasNext() {
	msg, err := reader.Next(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Received message msgId: %#v -- content: '%s'\n",
		msg.ID(), string(msg.Payload()))
}
```

The subscription type in the consumer example is pulsar.Shared, which distributes messages across the consumers attached to one subscription. The reader example starts at EarliestMessageID and loops on HasNext, so it drains the topic from the beginning rather than from wherever a cursor was left.

## Building and testing spins up a broker in a container

The Makefile drives the build with three targets, and the underlying commands are plain go build invocations:

```bash
	go build ./pulsar
	go build ./pulsaradmin
	go build -o bin/pulsar-perf ./perf
```

The three binaries are the client package, the admin command line tool and a performance binary. The same three builds run inside the repository Dockerfile, which also pulls the Pulsar server image, copies the integration test certificates, tokens and configuration into the broker, and sets the extra options for basic auth.

The test targets are driven by the Makefile rather than by go test directly, because the tests need a broker:

```bash
    make test
```

Both the Go version and the broker version can be pinned for a run:

```bash
    make test GO_VERSION=1.24 PULSAR_VERSION=4.0.3
```

The Makefile exposes the image names as variables, with the Go version defaulting to 1.25 and the Pulsar version defaulting to latest, and it derives the container architecture from the host with uname -m. Tests run inside a container that is removed after the run, and the race detector is enabled by default through a TEST_RACE variable, with coverage available behind TEST_COVERAGE.

The repository also ships a perf directory and an integration-tests directory, plus a golangci-lint configuration and a lint target, so static analysis is part of the same workflow rather than a separate setup.

## Upgrading can break on an old oauth2 module path

The troubleshooting section covers one failure mode that will hit anyone upgrading from an earlier version of the library, and it is worth knowing about before the build breaks rather than after.

The symptom is an ambiguous import error during a build:

```
github.com/apache/pulsar-client-go/oauth2: ambiguous import: found package github.com/apache/pulsar-client-go/oauth2 in multiple modules
```

The cause is a stale entry in go.mod pointing at the old oauth2 module path, which was a separate module before it moved into this repository. The fix is to remove references to that old path and then run go mod tidy:

```
github.com/apache/pulsar-client-go/oauth2 v0.0.0-20220630195735-e95cf0633348 // indirect
```

The oauth2 directory at the top level of the repository is now part of the main module, and the go.mod file lists golang.org/x/oauth2 among its direct requirements. An indirect reference to the old path is therefore a duplicate of a package that now lives in-tree.

The top-level layout explains the rest of the dependency picture. The pulsar/ directory is the client library itself, pulsaradmin/ is the admin command, oauth2/ holds the authentication provider, perf/ holds the performance tooling, distribution/ holds packaging material, and integration-tests/ holds the broker-side test setup.

## Parity with the other clients is tracked in a public matrix

Pulsar has several client libraries, and they are not interchangeable in feature coverage. The library therefore defers to the Client Feature Matrix hosted on the Pulsar site, which records which features each client supports, and tells you to look there for the supported feature set.

The contribution rules make that matrix part of the workflow rather than an afterthought. If a contribution adds Pulsar features for Go clients, you need to update both the Pulsar documentation and the Client Feature Matrix. That is a deliberate way of preventing the Go client from silently falling behind, and it tells you where to look before you commit to the library: the matrix shows exactly which broker capabilities you can rely on today.

The mailing lists are split by audience, with users@pulsar.apache.org for user questions and dev@pulsar.apache.org for development, both with subscribe and archive links, and there is a Slack channel named dev-go in the Apache Pulsar workspace with self-registration available.

For a team already running another Pulsar client, the matrix is the migration checklist. Comparing your current client's feature set against the Go one tells you which broker features you would lose, which is a more useful comparison than the general claim that the library is stable in production use.

## Version numbers stay below 1.0 while the API keeps moving

The release line is v0.x, with v0.21.0 published on 2026-07-31, v0.20.0 on 2026-06-15 and v0.19.0 on 2026-04-15. Three releases in roughly four months is a steady cadence for a client library, and the version numbers show that the project has not yet declared a stable 1.0 interface.

The repository is not archived, the default branch is master, and the last push was on 2026-10-20, so work continues right after the most recent release. A CHANGELOG.md sits at the root, which is where the interface changes between minor versions are recorded.

The dependencies are broad, which is expected for a client that speaks a binary protocol with authentication, compression and schema support in one package. The module requires the roaring bitmap library for cardinality work, lz4 and compress for payload compression, protobuf and avro for schemas, cobra for the admin command, prometheus client and logrus for instrumentation, and testcontainers-go for the integration test harness. It also pulls in the Athenz and DataDog zstd packages, which suggests support for the authentication and compression paths those ecosystems require.

For an adopter, the practical read is that you should pin a minor version and read the changelog before moving, and that a 0.x library from an active Apache project is a reasonable dependency with a real chance of interface churn between minor versions.

## Conclusion

pulsar-client-go suits a Go service that needs Pulsar without shipping a C++ toolchain or a cgo bridge, and that can live with the feature gaps listed in the client feature matrix. It does not suit a team that needs every broker feature today, because the library's own stated goal is to supersede the CGo-based client once feature parity and stability are reached, which has not happened yet. Before adopting it, compare the Client Feature Matrix against what your service uses, confirm Go 1.24 or newer is your floor, and check whether the oauth2 package you depend on comes from the in-tree module rather than the old path.

## FAQ

### What does the Apache Pulsar Go client library do?

It is a Go client library for Apache Pulsar, providing producers, subscriptions and readers that talk to a Pulsar broker. The library is pure Go and does not depend on the C++ Pulsar library.

### Does pulsar-client-go require cgo or a C++ toolchain?

No. The project states it is a pure-Go client library that does not depend on the C++ Pulsar library. The stated intent is that once feature parity and stability are reached it will supersede the current CGo-based library.

### What Go version does pulsar-client-go need?

The stated requirement is Go 1.24 or newer. The module file declares go 1.25.0, and the Makefile defaults the Go version to 1.25, so a build can be pinned with make test GO_VERSION=1.24 PULSAR_VERSION=4.0.3.

### How do I fix the ambiguous import error for the oauth2 package?

Remove any references to the old oauth2 module path from your go.mod file and then run go mod tidy. The oauth2 package now lives inside the main module, so an old indirect reference to github.com/apache/pulsar-client-go/oauth2 makes the package appear in two modules.

### How do I know which Pulsar features the Go client supports?

The documentation points to the Client Feature Matrix on the Pulsar site, which lists the supported Pulsar features for each client library. Contributions that add features must update both the Pulsar docs and that matrix.

## Sources

- [apache/pulsar-client-go on GitHub](https://github.com/apache/pulsar-client-go)
- [License: Apache-2.0](https://github.com/apache/pulsar-client-go/blob/master/LICENSE)
- [Project website](https://pulsar.apache.org/)
- [README](https://github.com/apache/pulsar-client-go/blob/master/README.md)
- [Releases](https://github.com/apache/pulsar-client-go/releases)

---

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