~/blog/2026/google-pubsub.md

Building a lightweight Google Pub/Sub emulator in Go

Why I replaced a 600 MB Java Docker image with a tiny Go binary — and how I kept full API compatibility.

gogrpcdockerpubsub

google-pubsub-emulator

The official Google Cloud Pub/Sub emulator works fine, but it comes with a cost: it's a Java application packaged in a Docker image that weighs around 600 MB. For local development or CI, that's a lot of overhead for something that just needs to shuffle messages around.

So I built a replacement in Go.

The goal

Full drop-in compatibility with the official emulator — meaning the cloud.google.com/go/pubsub client library should work against it without any changes. The same gRPC API, the same behaviour.

The result is a scratch-based Docker image with a single static binary.

What it supports

  • Full Publisher API — topics, publish, field-mask updates, retention policies
  • Full Subscriber API — pull, streaming pull, ack/nack, dead-letter topics, message ordering
  • Snapshots — create, seek-to-snapshot, seek-to-time
  • Init config — pre-create topics and subscriptions at startup via a YAML file

Init config

One feature I added on top: an init config that lets you declare your topics and subscriptions upfront, so you don't need setup scripts in your tests or local dev environment.

projects:
  - id: my-project
    topics:
      - name: orders
        subscriptions:
          - name: orders-processor
            ack_deadline_seconds: 30
docker run --rm -p 8085:8085 \
  -e INIT_CONFIG=/etc/pubsub/init.yaml \
  -v $(pwd)/init.yaml:/etc/pubsub/init.yaml:ro \
  ghcr.io/fbufler/google-pubsub:latest

How I validated it

I wrote an integration test suite and ran it against both the official Google emulator and mine. Same tests, same assertions. If it passes against Google's, it should pass against ours — and it does.

Proto toolchain

The gRPC server is generated from the official googleapis/googleapis proto definitions using buf and the connect-go plugin. Connect produces clean idiomatic Go and is fully gRPC-compatible, so existing clients work without modification.

Try it

docker run --rm -p 8085:8085 ghcr.io/fbufler/google-pubsub:latest
export PUBSUB_EMULATOR_HOST=localhost:8085

Source on GitHub. Apache 2.0 — and if you use it and we ever meet, buy me a beer.

main
dark