emitter.eventNames()
List every event name the emitter currently has at least one listener for.
emitter.eventNames()- Added in Node.js v6.0.0
Return value
<string>[] | <symbol>[]An array of the event names that currently have listeners, in the order the events were first subscribed to.
eventNames() returns the keys of the emitter's internal listener map: every event that currently has at least one listener. Events that were emitted but never subscribed to do not appear, and neither do events whose last listener was removed.
When to reach for it
Almost always for inspection. Dumping emitter.eventNames() in a debugger or a log line tells you at a glance what a stream, socket or bus is actually wired to, which is far more informative than guessing from the code. It is also the basis of generic tooling: forwarding every event from one emitter to another, or writing a teardown loop that clears each name in turn.
What trips people up
The array mixes strings and symbols. Node core and many libraries use symbol-keyed events for internals, so names.map(n => n.toUpperCase()) or a JSON.stringify() of the array will throw or silently drop entries. Filter by typeof, or call String(name), before treating them as text.
The array is a snapshot, not a live view, and it says nothing about how many listeners each name has — pair it with listenerCount() for that.
Example
When to use it
- Log what a socket or stream is subscribed to while debugging a hang
- Forward every event from an internal emitter onto a public one
- Write a generic teardown that loops over the names and clears each
Frequently asked questions
How do I list all events an EventEmitter is listening to?
Call emitter.eventNames(); it returns an array of the event names that currently have at least one listener. Events with no listeners never appear, so this reflects subscriptions rather than everything the object is capable of emitting.
Why does eventNames() contain symbols?
Because event names may be symbols, and Node core plus many libraries use symbol keys for internal events to avoid colliding with user-defined ones. Filter with typeof or convert with String(name) before doing anything string-specific with the array.
Does eventNames() show events that were emitted but never listened to?
No. The array is built from the emitter's listener map, so an event that was emitted with zero listeners leaves no trace. Use the boolean returned by emit() if you need to know whether a particular emission was heard.
More examples
Forwarding every event to another emitter
Because eventNames() reports both strings and symbols, this re-emitter works for symbol-keyed internal events too. The catch is that it only forwards names that already had a listener when forward() ran — events subscribed to later on `inner` are missed, so call it after wiring is complete.
const { EventEmitter } = require('node:events');
function forward(source, target) {
for (const name of source.eventNames()) {
source.on(name, (...args) => target.emit(name, ...args));
}
}
const inner = new EventEmitter();
inner.on('row', () => {});
inner.on('done', () => {});
const outer = new EventEmitter();
outer.on('row', (r) => console.log('outer saw row:', r));
outer.on('done', () => console.log('outer saw done'));
forward(inner, outer);
inner.emit('row', { id: 1 });
inner.emit('done');Inspecting what a core object listens for
A freshly created read stream already carries internal listeners of its own, so the first array is not empty. Mapping String over the names keeps the output readable when symbol keys are present, and pairing each name with listenerCount() turns the snapshot into a real subscription report — the quickest way to spot a duplicate handler on a core object.
const fs = require('node:fs');
const stream = fs.createReadStream('package.json');
console.log('after create:', stream.eventNames().map(String));
stream.on('data', () => {});
stream.on('error', () => {});
console.log('after subscribing:', stream.eventNames().map(String));
for (const name of stream.eventNames()) {
console.log(String(name), '->', stream.listenerCount(name));
}
stream.destroy();
Discussion