HazelJS LogoHazelJS
Introducing @hazeljs/pubsub: Google Cloud Messaging, HazelJS Style
HazelJS Blog

Introducing @hazeljs/pubsub: Google Cloud Messaging, HazelJS Style

Author
HazelJS Team
4/6/2026
General
← Back to Blog

Introducing @hazeljs/pubsub for HazelJS: decorator-based Google Cloud Pub/Sub consumers, typed publishing, ack/nack controls, and module-first integration.

Author: HazelJS Team

We’re shipping @hazeljs/pubsub — a Google Cloud Pub/Sub package for HazelJS with decorator-based consumers, typed publishing, and explicit ack/nack controls.

If your architecture already runs on GCP and Pub/Sub is your event backbone, this package gives you a native HazelJS developer experience without hand-wiring clients and handlers everywhere.


Why @hazeljs/pubsub?

Google Pub/Sub is a strong default for event-driven systems on GCP, but app code often ends up with repetitive setup:

  • create and share Pub/Sub clients manually
  • parse payloads in every handler
  • manually coordinate ack/nack behavior
  • wire subscriptions differently in each service

@hazeljs/pubsub standardizes this into one module + decorators + service pattern, consistent with the rest of HazelJS packages.


What’s in the box

PubSubModule

Configure once with forRoot() or forRootAsync() and use everywhere via DI.

PubSubPublisherService

Publish events from your controllers/services:

  • publish(topic, data, options?) for string/buffer/object payloads
  • publishJson(topic, data, options?) for JSON-first workflows

Decorator-based consumers

Define consumers declaratively:

  • @PubSubConsumer({...defaults}) at class level
  • @PubSubSubscribe({...}) at method level

Acknowledgement controls

Use defaults (ackOnSuccess, nackOnError) or control each message explicitly using:

  • return 'ack' | 'nack'
  • call payload.ack() / payload.nack()

Optional subscription auto-create

Enable autoCreateSubscription for bootstrap convenience when topic is provided.


Quick start

Install:

npm install @hazeljs/pubsub

Register the module:

@HazelModule({
  imports: [
    PubSubModule.forRoot({
      projectId: process.env.GCP_PROJECT_ID,
    }),
  ],
})
export class AppModule {}

Publish:

await this.publisher.publishJson('orders-topic', {
  id: 'ord_123',
  total: 149.99,
});

Consume:

@PubSubConsumer({ ackOnSuccess: true, nackOnError: true, parseJson: true })
@Service()
export class OrderConsumer {
  @PubSubSubscribe({
    subscription: 'orders-subscription',
    topic: 'orders-topic',
    autoCreateSubscription: true,
  })
  async handleOrder(payload: PubSubSubscriptionHandlerPayload<{ id: string; total: number }>) {
    // process payload.data
  }
}

When to use Pub/Sub vs Queue vs Kafka

  • Use @hazeljs/pubsub when you’re in GCP and want managed pub/sub semantics.
  • Use @hazeljs/queue for Redis-backed background jobs with BullMQ.
  • Use @hazeljs/kafka when Kafka is your event streaming platform.

Each package fits a different infrastructure shape, while keeping a familiar HazelJS module/decorator flow.


Production notes

  1. Keep handlers idempotent (at-least-once delivery can reprocess messages).
  2. Attach correlation IDs and metadata in message attributes.
  3. Monitor nack/error rates for early schema/runtime regressions.
  4. Prefer explicit retry/dead-letter handling in your platform-level design.

Read the docs

If you’re already using Pub/Sub in production, try it and share feedback in GitHub issues or Discord.