Introducing @hazeljs/pubsub: Google Cloud Messaging, HazelJS Style
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 payloadspublishJson(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/pubsubwhen you’re in GCP and want managed pub/sub semantics. - Use
@hazeljs/queuefor Redis-backed background jobs with BullMQ. - Use
@hazeljs/kafkawhen Kafka is your event streaming platform.
Each package fits a different infrastructure shape, while keeping a familiar HazelJS module/decorator flow.
Production notes
- Keep handlers idempotent (at-least-once delivery can reprocess messages).
- Attach correlation IDs and metadata in message attributes.
- Monitor nack/error rates for early schema/runtime regressions.
- Prefer explicit retry/dead-letter handling in your platform-level design.
Read the docs
- PubSub package docs: /docs/packages/pubsub
- NPM package: @hazeljs/pubsub
- Monorepo: hazel-js/hazeljs
If you’re already using Pub/Sub in production, try it and share feedback in GitHub issues or Discord.