thebus is a lightweight in-process pub/sub message bus for Go. It provides a dead-simple API, fast fan-out, configurable delivery strategies (shared vs. cloned payloads), and sensible defaults for safety and performance.
Just install thebus in your project by using the following command.
go get -u github.com/sebundefined/thebus
A minimal “hello world” pub/sub:
package main
import (
"context"
"fmt"
"time"
"github.com/sebundefined/thebus"
)
func main() {
// Create a new bus
bus, _ := thebus.New()
// Subscribe to a topic
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sub, _ := bus.Subscribe(ctx, "hello")
// Publish a message
_, _ = bus.Publish("hello", []byte("world"))
// Receive it
msg := <-sub.Read()
fmt.Printf("Got message on %s: %s\n", msg.Topic, msg.Payload)
// Graceful shutdown
_ = bus.Close()
}
You can configure the bus globally:
bus, _ := thebus.New(
thebus.WithMaxTopics(100),
thebus.WithCopyOnPublish(true), // safer if payloads are mutated after publish
)
Or customize subscribers
sub, _ := bus.Subscribe(ctx, "foo",
thebus.WithBufferSize(256),
thebus.WithSendTimeout(100*time.Millisecond),
thebus.WithStrategy(thebus.SubscriptionStrategyPayloadClonedPerSubscriber),
)
- ✅ Simple API (Publish, Subscribe, Unsubscribe, Stats, Close)
- 📦 Shared or cloned payload delivery strategies
- 🛡 Optional CopyOnPublish for safety against mutating payloads
- 📊 Backpressure & drop policies (DropIfFull, SendTimeout)
- 📉 Configurable limits (topics, subscribers per topic, buffer sizes)
- 🛑 Graceful shutdown with Close() and Unsubscribe()
- 🧪 Perfect for in-process events, simulations, and tests
- ⚡ Zero external deps (only stdlib crypto/rand)
We are using it at my current company for event driven within a single application. I decided to make it generic for publishing it to devs who need this kind of in-process system (adding config, per subscriber strategy...)
- Pure Go implementation — no broker required
- Lightweight alternative to Kafka/NATS when you just need local pub/sub
- Clean abstractions with good defaults
- Plays well with tests, mocks, and small services
go test -bench=. -benchmem -benchtime=2s ./...
goos: darwin
goarch: arm64
pkg: github.com/sebundefined/thebus
cpu: Apple M4 Pro
BenchmarkBus_Publish_NoSubscriber-14 62964634 38.04 ns/op 6729.34 MB/s 0 B/op 0 allocs/op
BenchmarkBus_Publish_CopyOnPublish_NoSubscriber-14 62382220 38.36 ns/op 6673.82 MB/s 0 B/op 0 allocs/op
BenchmarkBus_Publish_OneSubscriber-14 60785077 40.02 ns/op 6397.49 MB/s 0 B/op 0 allocs/op
BenchmarkBus_Publish_CopyOnPublish_OneSubscriber-14 60166773 39.96 ns/op 6406.85 MB/s 0 B/op 0 allocs/op
Run the full suite:
go test -race ./...
With coverage:
go test -race -count=1 -coverprofile=coverage.out ./...
thebus follows Semantic Versioning. Releases are published on GitHub and available via the Go module proxy.
Contributions are welcome! Please check CONTRIBUTING.md.