Skip to main content
The nestrs-microservices crate adds message-passing primitives on top of nestrs’s DI and module system. You annotate handler impl blocks with #[micro_routes] and individual methods with #[message_pattern] or #[event_pattern], then boot a transport server with one of the NestFactory::create_microservice_* constructors. The same module, provider, and injectable primitives you use for HTTP work exactly the same way in microservice mode.

Transport overview

Add the features you need to Cargo.toml:

Defining message handlers

Use #[micro_routes] on an impl block and #[message_pattern] / #[event_pattern] on individual methods. Message patterns expect a reply; event patterns are fire-and-forget:

Booting a TCP microservice

Booting a NATS microservice

Hybrid HTTP + microservice mode

Use also_listen_http to run the HTTP router and the microservice transport in the same process:
configure_http gives you the full NestApplication builder so you can apply all the usual HTTP middleware.

Sending messages with ClientsModule

Register downstream services in a module using ClientsModule::register. This exports a ClientsService (and a default ClientProxy when exactly one client is registered) into the DI container:
Inject ClientsService into a provider and use send_json for request/reply or emit_json for fire-and-forget:

gRPC transport

Enable the microservices-grpc feature and use the gRPC-specific factory and options:
For clients, use GrpcTransportOptions and chain .with_request_timeout for long-running RPCs:
The gRPC transport carries the same JSON wire format (WireRequest / WireResponse) inside protobuf bytes. Handler code is identical across transports — only the transport configuration changes.

Cross-cutting in micro handlers

On #[micro_routes] handlers, the execution order is:
Apply cross-cutting with the micro-specific attributes:
There is no microservice exception-filter pipeline. Handlers return Result<_, TransportError>. Guards and pipes return TransportError for early rejection. This differs from the HTTP pipeline where CanActivate flows through use_global_exception_filter.

Event bus (in-process)

For in-process async events without a transport, use EventBus directly:
Handlers annotated with #[on_event("...")] inside an #[event_routes] impl block are auto-subscribed at app boot.

Reliability guidance

  • Use emit_json for integration events (order.created, user.updated) and include an event_version field for forward compatibility.
  • Use send_json for request/reply patterns where a response contract is required.
  • Assume at-least-once delivery — keep handlers idempotent and include correlation IDs in payload metadata.
  • Add a dead-letter or retry strategy per transport adapter.
  • For critical integration events, use the outbox pattern: write business state and an outbox row in one DB transaction, then publish asynchronously with retries.