jsguides

events module

The events module is a core Node.js module that implements the observer pattern through the EventEmitter class. This module is the foundation of Node.js event-driven architecture—HTTP servers, streams, and the filesystem module all build on it. You can emit custom events and register listeners to respond to those events, enabling loose coupling between parts of your application.

Syntax

const EventEmitter = require('events');  // CommonJS
import { EventEmitter } from 'events';   // ESM

In CommonJS, the events module is globally available—you don’t need to install it. For ESM, import the EventEmitter class directly.

EventEmitter Class

The EventEmitter is the core class. It allows you to register listener functions that are called when a specific event is emitted.

Creating an EventEmitter

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();

Creating the emitter gives you an object with no listeners yet — it is an empty shell waiting for on or once calls to wire up behavior. The class-based approach is common in library code because it makes the emitter’s API part of the class contract.

emitter.on(eventName, listener)

Registers a listener function for the specified event. The listener is called every time the event is emitted.

ParameterTypeDefaultDescription
eventNamestring or symbolThe name of the event
listenerfunctionThe callback function (...args) => {}

Returns: EventEmitter — The emitter for chaining

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('greet', (name) => {
  console.log('Hello, ' + name);
});

emitter.emit('greet', 'Alice');

The call to emit synchronously invokes every listener registered for 'greet', passing 'Alice' as the argument. The output confirms the listener ran exactly once:

Hello, Alice

The listener receives the same arguments that were passed to emit after the event name. This forwarding mechanism is what makes event emitters useful for decoupled communication — the emitter does not need to know what the listener does with the data.

emitter.once(eventName, listener)

Registers a listener that is called at most once. After the first emission, the listener is removed automatically.

ParameterTypeDefaultDescription
eventNamestring or symbolThe name of the event
listenerfunctionThe callback function

Returns: EventEmitter

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.once('init', () => {
  console.log('Initialization complete');
});

emitter.emit('init');
emitter.emit('init'); // This emission is ignored

The first emit('init') triggers the listener. The second emit('init') finds no listeners attached, so nothing happens:

Initialization complete

This one-shot behavior makes once a natural fit for setup listeners, teardown handlers, and any callback that should fire only the first time an event occurs rather than on every subsequent emission.

emitter.emit(eventName[, …args])

Synchronously calls each listener registered for the event, passing the provided arguments.

ParameterTypeDefaultDescription
eventNamestring or symbolThe name of the event
...argsanyArguments passed to listeners

Returns: booleantrue if the event had listeners, false otherwise

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('data', (chunk) => {
  console.log('Received:', chunk);
});

const result = emitter.emit('data', 'Hello World');
console.log('Event had listeners:', result);

const noListeners = emitter.emit('nonexistent');
console.log('Nonexistent event:', noListeners);

The return value tells you whether anything was listening. This is handy for fallback logic — if the event goes unhandled, you can respond differently:

Received: Hello World
Event had listeners: true
Nonexistent event: false

emitter.off(eventName, listener)

Removes a specific listener from the event. Use this to clean up handlers you no longer need.

ParameterTypeDefaultDescription
eventNamestring or symbolThe event name
listenerfunctionThe listener function to remove

Returns: EventEmitter

const EventEmitter = require('events');

const emitter = new EventEmitter();

function handler(msg) {
  console.log('Handler 1:', msg);
}

emitter.on('message', handler);
emitter.emit('message', 'First');

emitter.off('message', handler);
emitter.emit('message', 'Second');

The second emit silently does nothing because the listener was already removed. Only the first emission produces output:

First

A function reference is required to remove it — anonymous arrow functions passed inline to on cannot be removed with off because there is no reference to compare.

emitter.removeListener(eventName, listener)

Alias for emitter.off(). Both methods do the same thing.

emitter.removeAllListeners([eventName])

Removes all listeners, or all listeners for a specified event. Use with caution — this breaks all registered handlers and can hide bugs if called unintentionally.

ParameterTypeDefaultDescription
eventNamestringoptionalIf omitted, removes all listeners from all events

Returns: EventEmitter

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('a', () => console.log('a'));
emitter.on('b', () => console.log('b'));
emitter.on('c', () => console.log('c'));

console.log('Before removeAllListeners:', emitter.listenerCount('a'));

emitter.removeAllListeners('a');
console.log('After removing a:', emitter.listenerCount('a'));
console.log('b still exists:', emitter.listenerCount('b'));

The targeted removal leaves other events intact — only the listeners for 'a' are wiped:

Before removeAllListeners: 1
After removing a: 0
b still exists: 1

emitter.listenerCount(eventName)

Returns the number of listeners registered for a given event.

ParameterTypeDefaultDescription
eventNamestringThe event to count

Returns: number

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('data', () => {});
emitter.on('data', () => {});
emitter.on('data', () => {});

console.log('Listener count:', emitter.listenerCount('data'));

Three listeners added, three listeners counted:

Listener count: 3

emitter.getMaxListeners()

Returns the current maximum listener number. The default is 10. You can change this with setMaxListeners().

Returns: number

const EventEmitter = require('events');

const emitter = new EventEmitter();
console.log('Default max listeners:', emitter.getMaxListeners());

Node prints a warning when you exceed this limit to help catch accidental memory leaks from forgotten listener registrations:

Default max listeners: 10

emitter.setMaxListeners(n)

Sets the maximum number of listeners. When more listeners are added than the limit, Node.js emits a warning to help detect memory leaks.

ParameterTypeDefaultDescription
nnumberMaximum number of listeners

Returns: EventEmitter

const EventEmitter = require('events');

const emitter = new EventEmitter();
emitter.setMaxListeners(20);
console.log('New max:', emitter.getMaxListeners());

The change takes effect immediately for the current emitter instance:

New max: 20

A common reason to raise the limit is when you expect many subscribers — for instance, a server event that triggers across dozens of modules. Set this before registering listeners so the warning never fires.

emitter.eventNames()

Returns an array of all registered event names.

Returns: Array<string | symbol>

const EventEmitter = require('events');

const emitter = new EventEmitter();
emitter.on('open', () => {});
emitter.on('close', () => {});
emitter.on('error', () => {});

console.log('Event names:', emitter.eventNames());

Each event type appears once regardless of how many listeners are attached:

Event names: [ 'open', 'close', 'error' ]

The return value from eventNames() is useful for debugging — you can print registered events to confirm your wiring is correct before emitting.

emitter.listeners(eventName)

Returns a copy of the array of listeners for the specified event.

ParameterTypeDefaultDescription
eventNamestringThe event name

Returns: function[]

Unlike listenerCount, this gives you the actual functions so you can inspect or invoke them directly. The returned array is a copy, so mutating it does not affect the emitter.

Error Events

When an error occurs within an EventEmitter, it emits an 'error' event. If no listener is registered for 'error', Node.js throws the error and may crash the process. Always handle error events in production code.

const EventEmitter = require('events');

const emitter = new EventEmitter();

emitter.on('error', (err) => {
  console.error('Error occurred:', err.message);
});

emitter.emit('error', new Error('Something went wrong'));

The error listener catches the emitted error and prints its message instead of letting it crash the process:

Error occurred: Something went wrong

Without the 'error' listener, that emit('error', ...) call would throw an unhandled error. The 'error' event is the only event in Node.js that triggers this special behavior — it is a safety mechanism, but one you must opt into.

Common Patterns

Inheriting from EventEmitter

Create custom classes that emit their own domain-specific events:

const EventEmitter = require('events');

class FileWatcher extends EventEmitter {
  constructor(filename) {
    super();
    this.filename = filename;
  }

  watch() {
    console.log('Watching ' + this.filename);
    setTimeout(() => {
      this.emit('change', { timestamp: Date.now() });
    }, 1000);
  }
}

const watcher = new FileWatcher('config.json');
watcher.on('change', (data) => {
  console.log('File changed at ' + data.timestamp);
});
watcher.watch();

The FileWatcher class inherits the on and emit methods from EventEmitter and adds its own watch method. When the timeout fires, the emitter notifies the listener with a data payload:

Watching config.json
File changed at 1709512345678

This pattern is the foundation of most Node.js core modules — http.Server, fs.ReadStream, and net.Socket all extend EventEmitter in exactly this way.

Using with EventEmitter.defaultMaxListeners

Change the default limit for all new emitters globally:

const { EventEmitter, defaultMaxListeners } = require('events');

console.log('Default maxListeners:', defaultMaxListeners);
// Increase global default
EventEmitter.defaultMaxListeners = 15;

Setting defaultMaxListeners affects every emitter created after the assignment, not just the current one. Use this sparingly — it is usually better to call setMaxListeners on individual emitters to avoid masking leaks across unrelated parts of the application.

See Also

  • stream – Stream-based processing with events
  • fs module – File system operations emit events