Message & Event Patterns
Message & Event Patterns
NestJS microservices communicate through two fundamental patterns: request-response (messages) and fire-and-forget (events). Choosing between them shapes how services stay decoupled, how errors propagate, and whether callers block waiting for a reply. Understanding both patterns — and the decorators and proxy methods that implement them — is the backbone of any NestJS microservice architecture.
@MessagePattern — Request-Response
A handler decorated with @MessagePattern participates in a request-response exchange. The caller sends a message and waits for a reply. This mirrors a traditional HTTP call: the client blocks (or awaits a Promise) until the remote handler returns or an error is thrown.
The pattern object ({ cmd: 'get_order' }) is the routing key. It can be a string literal or any serialisable object, as long as both sides agree on the same value.
@EventPattern — Fire-and-Forget
A handler decorated with @EventPattern receives events. The publisher does not wait for a response — it emits and moves on immediately. This is ideal for side-effects such as sending emails, updating read models, or writing audit logs, where the publisher has no interest in the outcome.
@MessagePattern when the caller needs a result.
ClientProxy — Sending from the Caller
On the calling side, inject a ClientProxy (produced by ClientsModule.register) and choose the matching method:
client.send(pattern, payload)— for@MessagePattern; returns an Observable that resolves with the reply.client.emit(pattern, payload)— for@EventPattern; returns an Observable that completes when the message is dispatched (not when handled).
ClientProxy.send() returns an RxJS Observable, not a Promise. Wrap it with firstValueFrom() (from rxjs) to use it comfortably inside async/await code. Do not ignore the subscription — an unsubscribed Observable never executes.
Payload & Context Handling
Use @Payload() to extract the message data and @Ctx() to access transport-specific context (headers, acknowledgement functions, partition info, etc.):
client.send() against a handler registered with @EventPattern will hang forever waiting for a reply that never comes. Calling client.emit() against a @MessagePattern handler means your reply is discarded — the caller gets nothing. Keep the pair consistent.
Summary
NestJS microservices offer two communication primitives: @MessagePattern + ClientProxy.send() for request-response (the caller awaits a reply), and @EventPattern + ClientProxy.emit() for fire-and-forget (no reply expected). Use @Payload() to access message data and @Ctx() for transport context. Always match the decorator on the handler with the correct proxy method on the caller — mismatches cause silent failures.