EventEmitterMuch of Node.js—including HTTP servers, streams, and child processes—is built around the EventEmitter pattern from node:events. An EventEmitter lets an object publish named events (emit) whenever something happens, while independent listener functions subscribe (on or once) and react without tight coupling.
Create a reusable event bus or extend EventEmitter in your own service class to decouple side effects like logging, emails, or metrics from core business steps.
import { EventEmitter } from 'node:events';
class OrderBus extends EventEmitter {}
const orderEvents = new OrderBus();
orderEvents.once('system:ready', () => {
console.log('Order listener initialized.');
});
orderEvents.on('order:paid', (order) => {
console.log(`Receipt queued for Order #${order.id} ($${order.total})`);
});
orderEvents.on('error', (err) => {
console.error('Handled emitter error:', err.message);
});
orderEvents.emit('system:ready');
orderEvents.emit('order:paid', { id: 501, total: 89.0 });
Use .once() for one-time startup hooks so the listener automatically removes itself immediately after firing once.
'error' EventDespite Node's asynchronous reputation, emitter.emit() invokes all registered listeners synchronously in the exact order they were attached. Additionally, if an EventEmitter emits an 'error' event with zero 'error' listeners attached, Node.js throws an uncaught exception and crashes the process—so always attach an 'error' handler on emitters you use.
.on() inside a request handler without removing it: Registering a new listener on a long-lived emitter on every HTTP request leaks memory and triggers MaxListenersExceededWarning after 11 listeners.'error' listener on streams or emitters: Unhandled 'error' events bring down your entire Node.js server.EventEmitter does not await async listener functions; wrap async listener bodies in try / catch.Pass the exact same named function reference to emitter.off('event', handlerFn) (inline anonymous arrow functions cannot be removed individually).
MaxListenersExceededWarning mean?By default, Node warns when more than 10 listeners subscribe to one event name on the same emitter, which usually signals a memory leak inside a loop or request handler.
events.once(emitter, 'ready') be awaited with Promises?Yes. import { once } from 'node:events' returns a Promise that resolves when the event fires (or rejects if 'error' fires first).
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.