@nestjs/event-emitter

Event-driven architecture for NestJS, built on EventEmitter2

Library
npm
v12.0.1
251 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
81 /100 Excellent
Development Activity 96
Maintenance 84
Community 64
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
77 /100 Good
Architecture 80
Code Quality 78
Innovation 68
Learning Curve 82

@nestjs/event-emitter wires the battle-tested eventemitter2 library into the Nest dependency-injection system, giving Nest applications a first-class in-process event bus. Instead of manually wiring listeners, providers declare @OnEvent() handlers that are automatically discovered and registered at bootstrap via Nest’s DiscoveryModule, letting different parts of an application communicate through fire-and-forget or awaited events rather than direct service-to-service calls.

This decoupling is especially useful for side effects that shouldn’t block a primary request path — sending a welcome email after signup, invalidating a cache after an update, or triggering a background job after a domain event — while still keeping everything inside a single process and fully typed.

What You Get

  • A global, injectable EventEmitter2 instance shared across the whole Nest application
  • @OnEvent() method decorator for declaring listeners anywhere in the DI graph, including request-scoped providers
  • Automatic listener discovery at bootstrap via Nest’s DiscoveryModule, no manual registration needed
  • Support for wildcard event names, async/awaited listeners, and listener priority/ordering options inherited from eventemitter2
  • EventEmitterReadinessWatcher to ensure listeners are fully wired before events are emitted during startup

Common Use Cases

  • Firing a user.created event after signup and having separate providers send a welcome email and provision default resources
  • Decoupling domain logic from side effects like audit logging, cache invalidation, or webhook dispatch
  • Coordinating request-scoped or durable-request-scoped providers that need to react to events within the same request context
  • Building a lightweight in-process pub/sub layer before introducing an external message broker

Under The Hood

Architecture - The module is a thin Nest-native wrapper around eventemitter2: EventEmitterModule.forRoot() registers a DiscoveryModule import plus providers for EventSubscribersLoader, EventsMetadataAccessor, and EventEmitterReadinessWatcher, and provides a single EventEmitter2 instance via a factory so it can be injected anywhere. At bootstrap, EventSubscribersLoader uses Nest’s DiscoveryService to walk every registered provider and controller, find methods carrying @OnEvent() metadata (read via EventsMetadataAccessor), and bind them onto the shared EventEmitter2 instance, including handling for request-scoped and durable-request-scoped providers so listeners resolve the correct instance per request.

Tech Stack - Built in TypeScript on top of eventemitter2 (the only runtime dependency) and Nest’s own @nestjs/common/@nestjs/core as peer dependencies; internal tooling uses oxlint for linting, vitest for e2e tests, and release-it plus Husky/commitlint for a conventional-commit release flow, reflecting the same tooling conventions used across the core NestJS org repos.

Code Quality - The tests/e2e suite exercises the module end-to-end against a real Nest TestingModule (module-e2e.spec.ts, inherit-context-id.spec.ts), covering request-scoped and durable-request-scoped consumer patterns, aliased providers, and custom decorators rather than just unit-testing the emitter in isolation. Source files are small and single-purpose (loader, accessor, watcher, module each in their own file), consistent with Nest’s own module conventions, though there is no explicit runtime validation of event payload shapes beyond what TypeScript enforces at compile time.

API Design - The public surface is intentionally minimal: one module import, one decorator (@OnEvent), and the underlying EventEmitter2 API for emitting. This keeps boilerplate low for consumers already familiar with Nest’s decorator-and-DI conventions, at the cost of relying on string event names with no first-class type-safe event map out of the box.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers