Durable messaging for NestJS microservices
A NestJS transport for NATS JetStream. Keep @EventPattern, @MessagePattern and ClientProxy as they are: messages persist across deploys, failed handlers retry, and what still fails is kept for you to inspect.
Built for NestJS
Runs on NATS JetStream
- v3.0.0
- NestJS 10, 11, 12
- NATS ≥ 2.10
- Node ≥ 22
- MIT
Nothing lost on deploy
A message stays in a JetStream stream until a handler acks it. If the pod restarts mid-handler, another replica picks the message up.
Failures have somewhere to go
A throw retries after 2 s, then 10 s. A message that still fails is kept in a dead-letter stream with its headers, never dropped.
The NestJS API you already use
Handlers, ClientProxy and exception filters stay as they are. What changes is the module you import.
When the built-in transport is not enough
NestJS ships a NATS transport on Core NATS: fast, and fire and forget. It suits cache invalidations and other messages you can afford to lose. For work that must happen, this library adds what Core NATS leaves out.
Read the full comparison| Capability | Transport.NATS | nestjs-jetstream |
|---|---|---|
| @EventPattern, @MessagePattern and ClientProxy | ✓ | ✓ |
| Low-latency request and reply | ✓ | ✓ |
| Messages survive a restart | – | ✓ |
| Retries when a handler throws | – | ✓ |
| Dead-letter stream | – | ✓ |
| Broadcast with catch-up for late replicas | – | ✓ |
| Replay of past events | – | ✓ |
| Cron and delayed delivery | – | ✓ |
| OpenTelemetry tracing and Prometheus metrics | – | ✓ |
Switching is a module swap
- Install the package. The NATS client comes with it.
- Swap the module. forRoot for the service, forFeature for each target it calls.
- Connect the transport. One connectMicroservice call in main.ts.
- Keep your handlers. Make them idempotent: delivery is now at least once.
ClientsModule.register([{ name: 'ORDERS', transport: Transport.NATS }]), JetstreamModule.forRoot({ name: 'orders', servers }), JetstreamModule.forFeature({ name: 'orders' }),
What is in the box
- Workqueue eventsEach message reaches one replica, at least once.
- RPCCore NATS for latency or JetStream for durability, per module.
- BroadcastEvery service gets every message, late replicas included.
- Ordered eventsA strict, replayable sequence for projections and caches.
- Dead-letter queueExhausted messages kept with headers and delivery count.
- Cron and delayed jobsFired by NATS itself, with no scheduler process to run.
- Tracing and metricsW3C trace context across hops, Prometheus metrics built in.
- Health and shutdownKubernetes probes, and in-flight work drained on SIGTERM.
- Multiple clustersOne service talking to several NATS clusters at once.
Run your first durable handler
The quick start takes about five minutes against a local NATS in Docker.