Skip to main content
v2.13.0·MIT·coverage

nestjs-jetstream

A NATS JetStream transport for NestJS. Durable streams, bounded retries, and W3C trace context — behind the same @EventPattern decorators you already use.

npm i @horizon-republic/nestjs-jetstreamMITNode 20NestJS 10+
What's inside

Five primitives.

Each one sits behind the NestJS decorators you already use. The library handles the JetStream details.

At-least-once delivery, bounded retries

Every event is acknowledged after the handler returns. Failures retry with exponential backoff and land in a typed dead-letter queue if the budget is exhausted.

Broadcast fan-out across replicas

One @Broadcast() event reaches every running pod — with no double-processing on the workqueue side.

RPC over Core & JetStream

Request/reply with timeouts, typed responses, and the RecordBuilder for headers.

Distributed tracing, on by default

W3C traceparent propagated through every hop. Wire to OpenTelemetry in three lines.

Ordered delivery per partition

Stable subject keys give you single-consumer ordering without giving up horizontal scale on the rest of the workload.

orders.42orders.42 →orders.42
In code

Register the module, decorate handlers.

The surface area you already use in @nestjs/microservices. JetStream lives underneath.

app.module.tsTypeScript
import { Module } from '@nestjs/common';
import { JetstreamModule } from '@horizon-republic/nestjs-jetstream';

@Module({
  imports: [
    JetstreamModule.forRoot({
      servers: ['nats://localhost:4222'],
    }),
  ],
})
export class AppModule {}
orders.controller.tsTypeScript
import { Controller, Logger } from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';

// At-least-once. Retries on throw. Traced end-to-end.
@Controller()
export class OrdersController {
  private readonly log = new Logger(OrdersController.name);

  @EventPattern('orders.created')
  async onCreated(@Payload() order: Order) {
    await this.billing.charge(order);
    this.log.log(`charged ${order.id}`);
  }

  @MessagePattern('orders.lookup')
  lookup(@Payload() id: string) {
    return this.orders.find(id);
  }
}
Architecture

Sits between your application and the stream.

Provisions streams & consumers on boot, routes messages to decorated handlers, drains cleanly on shutdown.

PUBLISHER · NESTJSapi-gatewayclient.emit( 'orders.created', order);ClientProxy + tracingLIBRARY · @horizon-republic/nestjs-jetstreamforRoot()forFeature()StrategyCodecAck · retry · DLQ · ordered · broadcast · RPC · trace contextCONSUMER · NESTJSorders-svc@EventPattern( 'orders.created')onCreated(o) { … }ack · retry · DLQNATS SERVER · JETSTREAMstream: orders · subjects: orders.> · replicas: 3 · workqueueemitdeliver
Publish → stream → consumer. The library owns provisioning, routing, retries, and tracing on both sides.

Quick start.

Drops into your existing NestJS module graph.