NestJS Event-Driven Pattern

VerifiedSafe

Build event-driven systems with EventEmitter2, CQRS module, CommandBus, and QueryBus.

Sby Skills Guide Bot
DevelopmentIntermediate
7/27/2026
Claude CodeCursorWindsurfCopilotCodex
#nestjs#event-driven#cqrs#event-emitter#typescript

Recommended for

Automated summary

A reference for building event-driven architectures in NestJS with EventEmitter2 and the CQRS module (CommandBus, QueryBus, EventBus, sagas).

Strengths

  • Covers two complementary approaches (EventEmitter2 for in-process pub/sub, CQRS for separating reads and writes) with copy-ready code excerpts
  • Explains practical pitfalls: async handlers via async/promisify, event wildcards, and registering handlers in providers
  • Honestly frames the in-process limitation and points to microservices transports, Kafka or NATS for cross-service events

Limitations

  • Deliberately condensed: the saga pattern is only mentioned, with no code example
  • Does not address event persistence, idempotency, or retry strategies needed for real event sourcing
  • Assumes an existing NestJS + Prisma stack and does not detail module configuration
When to use it

Use it when designing or refactoring a NestJS service to decouple side effects or introduce command/query separation.

When not to use it

Avoid it if you need a full event-sourcing guide with persistence, event replay and delivery guarantees, or if you are not using NestJS.

Security analysis

Safe
Quality score85/100

This is a documentation-only reference skill describing NestJS event-driven patterns (EventEmitter2, CQRS, sagas). It contains no executable actions, no destructive commands, no network exfiltration, and no attempts to disable safety controls. The only shell snippets are standard npm installs of official NestJS packages.

No concerns found

How this analysis is made

Examples

Découpler l'envoi d'email
Dans mon service NestJS, après la création d'un utilisateur je veux envoyer un email de bienvenue et écrire un log d'audit sans bloquer la requête. Montre-moi comment faire avec @nestjs/event-emitter.
Introduire CQRS
Refactorise mon UsersController NestJS pour utiliser CommandBus et QueryBus du module @nestjs/cqrs, avec un CreateUserHandler et un GetUserHandler.
Choisir entre EventEmitter2 et CQRS
Explique-moi quand utiliser EventEmitter2 plutôt que le module CQRS dans NestJS, et donne un exemple de EventBus pour publier un événement de domaine.

NestJS Event-Driven Pattern

Build event-driven systems with EventEmitter2, CQRS module, CommandBus, and QueryBus

When to Use

  • You need to decouple side effects (send email, update audit log) from the primary operation
  • You are implementing CQRS to separate read and write models for a bounded context
  • You need event sourcing where domain events are the source of truth
  • You want to publish domain events that multiple services can independently handle

Instructions

EventEmitter2 (simple pub/sub within the same process)

  1. Setup:
npm install @nestjs/event-emitter
@Module({ imports: [EventEmitterModule.forRoot()] })
export class AppModule {}
  1. Emit events from a service:
@Injectable()
export class UsersService {
  constructor(private eventEmitter: EventEmitter2) {}

  async create(dto: CreateUserDto): Promise<User> {
    const user = await this.prisma.user.create({ data: dto });
    this.eventEmitter.emit('user.created', new UserCreatedEvent(user));
    return user;
  }
}
  1. Handle events:
@Injectable()
export class EmailNotificationListener {
  @OnEvent('user.created')
  async handleUserCreated(event: UserCreatedEvent): Promise<void> {
    await this.mailService.sendWelcomeEmail(event.user.email);
  }

  @OnEvent('user.*') // wildcard
  async handleAnyUserEvent(event: unknown): Promise<void> { ... }
}

CQRS Module (commands and queries)

npm install @nestjs/cqrs
// command
export class CreateUserCommand { constructor(public dto: CreateUserDto) {} }

// handler
@CommandHandler(CreateUserCommand)
export class CreateUserHandler implements ICommandHandler<CreateUserCommand> {
  constructor(private usersRepo: UsersRepository) {}
  async execute(command: CreateUserCommand): Promise<User> {
    return this.usersRepo.create(command.dto);
  }
}

// dispatch from controller
@Post()
create(@Body() dto: CreateUserDto) {
  return this.commandBus.execute(new CreateUserCommand(dto));
}

// query
@QueryHandler(GetUserQuery)
export class GetUserHandler implements IQueryHandler<GetUserQuery> {
  async execute(query: GetUserQuery): Promise<User> {
    return this.usersReadRepo.findById(query.id);
  }
}

Register all handlers in providers.

Details

EventEmitter2 vs CQRS: EventEmitter2 is in-process pub/sub — simple, zero setup overhead, good for side effects. CQRS is a structural pattern that separates commands (writes) from queries (reads) — use it when you need independent scaling of read/write paths or when the read model differs significantly from the write model.

EventEmitter2 async handlers: @OnEvent('user.created', { async: true }) ensures async handlers do not block the event loop. Set promisify: true on EventEmitterModule.forRoot() to await async handlers before continuing.

EventBus (CQRS): In addition to CommandBus and QueryBus, the CQRS module provides EventBus for domain events. IEventHandler implementations react to events published via eventBus.publish(new UserCreatedEvent(user)).

Saga pattern: @nestjs/cqrs supports long-running processes via @Saga() decorator — these are RxJS streams that react to events and dispatch commands.

Cross-service events: EventEmitter2 is in-process only. For cross-service messaging (microservices), use the NestJS microservices transport layer (@EventPattern, Redis/RabbitMQ) or integrate with Kafka/NATS for durable event streams.

Source

https://docs.nestjs.com/recipes/cqrs

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. Verify your implementation against the details and edge cases listed above.

Harness Integration

  • Type: knowledge — this skill is a reference document, not a procedural workflow.
  • No tools or state — consumed as context by other skills and agents.

Success Criteria

  • The patterns described in this document are applied correctly in the implementation.
  • Edge cases and anti-patterns listed in this document are avoided.

From the file to a first result

The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.

View the source and supporting files

This download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.

1. Download the file

Download SKILL.md

From the root of a test project, save the file as .skill-downloads/nestjs-event-driven-pattern-ms2s7cy8/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.

Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.

mkdir -p '.skill-downloads/nestjs-event-driven-pattern-ms2s7cy8' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/nestjs-event-driven-pattern-ms2s7cy8/download' --output '.skill-downloads/nestjs-event-driven-pattern-ms2s7cy8/SKILL.md.part' && mv '.skill-downloads/nestjs-event-driven-pattern-ms2s7cy8/SKILL.md.part' '.skill-downloads/nestjs-event-driven-pattern-ms2s7cy8/SKILL.md'

2. Check prerequisites

Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.

No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.

The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.

3. Load the skill

This file does not provide a usable name/description header for this native procedure. It remains available to download and inspect; use the manual method below.

Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.

4. Try a first task

Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:

Read .skill-downloads/nestjs-event-driven-pattern-ms2s7cy8/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.

Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.

Related skills