KubeMQ
IntegrationsNestJSTutorials

Getting Started with NestJS

Install the transport and build a first end-to-end NestJS app that sends and handles a KubeMQ command in under 5 minutes.

Implementation steps

Prerequisites

Before you start, make sure you have:

RequirementDetails
Node.js20.11.0 or later
NestJS appAn existing project, or create one with nest new my-app
KubeMQ brokerA running broker reachable on localhost:50000

If you do not have a broker yet, start one locally with Docker:

docker run -d \  --name kubemq \  -p 50000:50000 \  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \  europe-docker.pkg.dev/kubemq/images/kubemq:next

Port 50000 is the gRPC port the transport connects to. The @kubemq/nestjs-transport package is built on the native kubemq-js SDK, so no HTTP connector flag is required.

Install the Transport

Add the transport and its kubemq-js runtime dependency:

npm install @kubemq/nestjs-transport kubemq-js

Most of the peer dependencies already ship with a typical NestJS project. Install any that are missing:

npm install @nestjs/common @nestjs/core @nestjs/microservices rxjs reflect-metadata

The package exposes two optional subpath entry points: @kubemq/nestjs-transport/testing (mocks for unit tests) and @kubemq/nestjs-transport/cqrs (the @nestjs/cqrs bridge). They are only needed for those specific features and pull in their own optional peer dependencies (@nestjs/terminus for health checks, @nestjs/cqrs for the CQRS bridge).

Register the Module

In your root module, register a global connection with forRoot and a named client with register. The global connection is shared across the app; the named client is the proxy you inject to send messages.

app.module.ts
import { Module } from '@nestjs/common';
import { KubeMQModule } from '@kubemq/nestjs-transport';
import { OrderHandler } from './order.handler';
import { OrderService } from './order.service';

const address = process.env.KUBEMQ_ADDRESS ?? 'localhost:50000';

@Module({
  imports: [
    KubeMQModule.forRoot({
      address,
      clientId: 'orders-app',
      isGlobal: true,
    }),
    KubeMQModule.register({
      name: 'KUBEMQ_SERVICE',
      address,
      clientId: 'orders-client',
    }),
  ],
  providers: [OrderHandler, OrderService],
})
export class AppModule {}

The name you pass to register (here 'KUBEMQ_SERVICE') is the injection token you will use to inject the client in Step 6.

Add a Command Handler

Create a handler that responds to the orders.create channel. Use @CommandHandler for the channel, @Payload() to bind the message body, and @Ctx() to access the KubeMQCommandContext. Returning a value from the method sends it back as the command response.

order.handler.ts
import { Injectable, Logger } from '@nestjs/common';
import { CommandHandler, KubeMQCommandContext } from '@kubemq/nestjs-transport';
import { Payload, Ctx } from '@nestjs/microservices';

@Injectable()
export class OrderHandler {
  private readonly logger = new Logger(OrderHandler.name);

  @CommandHandler('orders.create')
  handleCreate(
    @Payload() data: { name: string; total: number },
    @Ctx() ctx: KubeMQCommandContext,
  ) {
    this.logger.log(`Command from ${ctx.fromClientId} on ${ctx.channel}`);
    return { orderId: 'order-123', status: 'created' };
  }
}

The handler class must be a NestJS-managed provider. If the decorator never fires, the most common cause is a class that is not listed in a module's providers (the class is @Injectable() and the module imports KubeMQModule). A standalone class instantiated outside Nest will not be wired to the transport.

Bootstrap the Hybrid App

A NestJS hybrid app serves both HTTP and the KubeMQ microservice transport. Attach the KubeMQServer strategy with connectMicroservice, start the microservices, then start the HTTP listener.

main.ts
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { KubeMQServer } from '@kubemq/nestjs-transport';
import { AppModule } from './app.module';

const address = process.env.KUBEMQ_ADDRESS ?? 'localhost:50000';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.connectMicroservice({
    strategy: new KubeMQServer({
      address,
      clientId: 'orders-server',
      group: 'orders-group',
    }),
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

The group option puts the server in a consumer group, so multiple replicas load-balance command delivery instead of each receiving a copy.

Send From a Service

Inject the named client by its token and call send for request-reply. send returns an RxJS Observable, so wrap it in firstValueFrom to await the single response.

order.service.ts
import { Injectable, Inject, Logger } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class OrderService {
  private readonly logger = new Logger(OrderService.name);

  constructor(@Inject('KUBEMQ_SERVICE') private readonly client: ClientProxy) {}

  async createOrder(data: { name: string; total: number }) {
    const response = await firstValueFrom(
      this.client.send('orders.create', data),
    );
    this.logger.log(`Command response: ${JSON.stringify(response)}`);
    return response;
  }
}

By default client.send() sends a Command and client.emit() sends an Event. To send a Query, Events Store message, or Queue message instead, wrap the payload in a KubeMQRecord — see Usage.

Run It

The repository ships a large examples corpus where every folder is a self-contained NestJS mini-app. The fastest way to see a working command round-trip is the rpc/send-command example, which registers a handler and a sender in the same app:

cd examples
npm install
npx tsx examples/rpc/send-command/main.ts

Expected output:

[SendCommandExample] KubeMQ microservice started
[CommandService] Sending command...
[CommandHandler] Received command on nestjs-rpc.send-command: {"action":"create-user","name":"Alice"}
[CommandService] Command response: {"executed":true,"action":"create-user"}

To see all five handler decorators (@CommandHandler, @QueryHandler, @EventHandler, @EventStoreHandler, @QueueHandler) exercised in one application, run the decorators/all-handlers example:

npx tsx examples/decorators/all-handlers/main.ts

Every example reads the broker address from the KUBEMQ_ADDRESS environment variable and falls back to localhost:50000. To target a remote broker, export the variable before running: KUBEMQ_ADDRESS=my-broker:50000 npx tsx examples/rpc/send-command/main.ts.

Was this page helpful?

On this page