Events#

Stability: 2 - Stable

Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture in which certain kinds of objects (called "emitters") emit named events that cause Function objects ("listeners") to be called.

For instance: a net.Server object emits an event each time a peer connects to it; a fs.ReadStream emits an event when the file is opened; a stream emits an event whenever data is available to be read.

All objects that emit events are instances of the EventEmitter class. These objects expose an eventEmitter.on() function that allows one or more functions to be attached to named events emitted by the object. Typically, event names are camel-cased strings but any valid JavaScript property key can be used.

When the EventEmitter object emits an event, all of the functions attached to that specific event are called synchronously. Any values returned by the called listeners are ignored and discarded.

The following example shows a simple EventEmitter instance with a single listener. The eventEmitter.on() method is used to register listeners, while the eventEmitter.emit() method is used to trigger the event.

import { EventEmitter } from 'node:events';

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');
const EventEmitter = require('node:events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');
javascript

Passing arguments and this to listeners#

The eventEmitter.emit() method allows an arbitrary set of arguments to be passed to the listener functions. Keep in mind that when an ordinary listener function is called, the standard this keyword is intentionally set to reference the EventEmitter instance to which the listener is attached.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
  console.log(a, b, this, this === myEmitter);
  // Prints:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     Symbol(shapeMode): false,
  //     Symbol(kCapture): false
  //   } true
});
myEmitter.emit('event', 'a', 'b');
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
  console.log(a, b, this, this === myEmitter);
  // Prints:
  //   a b MyEmitter {
  //     _events: [Object: null prototype] { event: [Function (anonymous)] },
  //     _eventsCount: 1,
  //     _maxListeners: undefined,
  //     Symbol(shapeMode): false,
  //     Symbol(kCapture): false
  //   } true
});
myEmitter.emit('event', 'a', 'b');
javascript

It is possible to use ES6 Arrow Functions as listeners, however, when doing so, the this keyword will no longer reference the EventEmitter instance:

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b undefined
});
myEmitter.emit('event', 'a', 'b');
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b {}
});
myEmitter.emit('event', 'a', 'b');
javascript

Asynchronous vs. synchronous#

The EventEmitter calls all listeners synchronously in the order in which they were registered. This ensures the proper sequencing of events and helps avoid race conditions and logic errors. When appropriate, listener functions can switch to an asynchronous mode of operation using the setImmediate() or process.nextTick() methods:

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('this happens asynchronously');
  });
});
myEmitter.emit('event', 'a', 'b');
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  setImmediate(() => {
    console.log('this happens asynchronously');
  });
});
myEmitter.emit('event', 'a', 'b');
javascript

Handling events only once#

When a listener is registered using the eventEmitter.on() method, that listener is invoked every time the named event is emitted.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.on('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Prints: 2
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.on('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Prints: 2
javascript

Using the eventEmitter.once() method, it is possible to register a listener that is called at most once for a particular event. Once the event is emitted, the listener is unregistered and then called.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
  console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored
javascript

Error events#

When an error occurs within an EventEmitter instance, the typical action is for an 'error' event to be emitted. These are treated as special cases within Node.js.

If an EventEmitter does not have at least one listener registered for the 'error' event, and an 'error' event is emitted, the error is thrown, a stack trace is printed, and the Node.js process exits.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// Throws and crashes Node.js
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// Throws and crashes Node.js
javascript

To guard against crashing the Node.js process the domain module can be used. (Note, however, that the node:domain module is deprecated.)

As a best practice, listeners should always be added for the 'error' events.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
  console.error('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
// Prints: whoops! there was an error
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
  console.error('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
// Prints: whoops! there was an error
javascript

It is possible to monitor 'error' events without consuming the emitted error by installing a listener using the symbol events.errorMonitor.

import { EventEmitter, errorMonitor } from 'node:events';

const myEmitter = new EventEmitter();
myEmitter.on(errorMonitor, (err) => {
  MyMonitoringTool.log(err);
});
myEmitter.emit('error', new Error('whoops!'));
// Still throws and crashes Node.js
const { EventEmitter, errorMonitor } = require('node:events');

const myEmitter = new EventEmitter();
myEmitter.on(errorMonitor, (err) => {
  MyMonitoringTool.log(err);
});
myEmitter.emit('error', new Error('whoops!'));
// Still throws and crashes Node.js
javascript

Capture rejections of promises#

Using async functions with event handlers is problematic, because it can lead to an unhandled rejection in case of a thrown exception:

import { EventEmitter } from 'node:events';
const ee = new EventEmitter();
ee.on('something', async (value) => {
  throw new Error('kaboom');
});
const EventEmitter = require('node:events');
const ee = new EventEmitter();
ee.on('something', async (value) => {
  throw new Error('kaboom');
});
javascript

The captureRejections option in the EventEmitter constructor or the global setting change this behavior, installing a .then(undefined, handler) handler on the Promise. This handler routes the exception asynchronously to the Symbol.for('nodejs.rejection') method if there is one, or to 'error' event handler if there is none.

import { EventEmitter } from 'node:events';
const ee1 = new EventEmitter({ captureRejections: true });
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);

const ee2 = new EventEmitter({ captureRejections: true });
ee2.on('something', async (value) => {
  throw new Error('kaboom');
});

ee2[Symbol.for('nodejs.rejection')] = console.log;
const EventEmitter = require('node:events');
const ee1 = new EventEmitter({ captureRejections: true });
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);

const ee2 = new EventEmitter({ captureRejections: true });
ee2.on('something', async (value) => {
  throw new Error('kaboom');
});

ee2[Symbol.for('nodejs.rejection')] = console.log;
javascript

Setting events.captureRejections = true will change the default for all new instances of EventEmitter.

import { EventEmitter } from 'node:events';

EventEmitter.captureRejections = true;
const ee1 = new EventEmitter();
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);
const events = require('node:events');
events.captureRejections = true;
const ee1 = new events.EventEmitter();
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);
javascript

The 'error' events that are generated by the captureRejections behavior do not have a catch handler to avoid infinite error loops: the recommendation is to not use async functions as 'error' event handlers.

Class: EventEmitter#

The EventEmitter class is defined and exposed by the node:events module:

import { EventEmitter } from 'node:events';
const EventEmitter = require('node:events');
javascript

All EventEmitters emit the event 'newListener' when new listeners are added and 'removeListener' when existing listeners are removed.

It supports the following option:

Event: 'newListener'#

The EventEmitter instance will emit its own 'newListener' event before a listener is added to its internal array of listeners.

Listeners registered for the 'newListener' event are passed the event name and a reference to the listener being added.

The fact that the event is triggered before adding the listener has a subtle but important side effect: any additional listeners registered to the same name within the 'newListener' callback are inserted before the listener that is in the process of being added.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Insert a new listener in front
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');
// Prints:
//   B
//   A
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // Insert a new listener in front
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');
// Prints:
//   B
//   A
javascript

Event: 'removeListener'#

The 'removeListener' event is emitted after the listener is removed.

emitter.addListener(eventName, listener)#

Alias for emitter.on(eventName, listener).

emitter.emit(eventName[, ...args])#

Synchronously calls each of the listeners registered for the event named eventName, in the order they were registered, passing the supplied arguments to each.

Returns true if the event had listeners, false otherwise.

import { EventEmitter } from 'node:events';
const myEmitter = new EventEmitter();

// First listener
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! first listener');
});
// Second listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
});
// Third listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ');
  console.log(`event with parameters ${parameters} in third listener`);
});

console.log(myEmitter.listeners('event'));

myEmitter.emit('event', 1, 2, 3, 4, 5);

// Prints:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! first listener
// event with parameters 1, 2 in second listener
// event with parameters 1, 2, 3, 4, 5 in third listener
const EventEmitter = require('node:events');
const myEmitter = new EventEmitter();

// First listener
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! first listener');
});
// Second listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`event with parameters ${arg1}, ${arg2} in second listener`);
});
// Third listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ');
  console.log(`event with parameters ${parameters} in third listener`);
});

console.log(myEmitter.listeners('event'));

myEmitter.emit('event', 1, 2, 3, 4, 5);

// Prints:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! first listener
// event with parameters 1, 2 in second listener
// event with parameters 1, 2, 3, 4, 5 in third listener
javascript

emitter.eventNames()#

Returns an array listing the events for which the emitter has registered listeners.

import { EventEmitter } from 'node:events';

const myEE = new EventEmitter();
myEE.on('foo', () => {});
myEE.on('bar', () => {});

const sym = Symbol('symbol');
myEE.on(sym, () => {});

console.log(myEE.eventNames());
// Prints: [ 'foo', 'bar', Symbol(symbol) ]
const EventEmitter = require('node:events');

const myEE = new EventEmitter();
myEE.on('foo', () => {});
myEE.on('bar', () => {});

const sym = Symbol('symbol');
myEE.on(sym, () => {});

console.log(myEE.eventNames());
// Prints: [ 'foo', 'bar', Symbol(symbol) ]
javascript

emitter.getMaxListeners()#

Returns the current max listener value for the EventEmitter which is either set by emitter.setMaxListeners(n) or defaults to events.defaultMaxListeners.

emitter.listenerCount(eventName[, listener])#

Returns the number of listeners listening for the event named eventName. If listener is provided, it will return how many times the listener is found in the list of the listeners of the event.

emitter.listeners(eventName)#

Returns a copy of the array of listeners for the event named eventName.

server.on('connection', (stream) => {
  console.log('someone connected!');
});
console.log(util.inspect(server.listeners('connection')));
// Prints: [ [Function] ]
js

emitter.off(eventName, listener)#

Alias for emitter.removeListener().

emitter.on(eventName, listener)#

Adds the listener function to the end of the listeners array for the event named eventName. No checks are made to see if the listener has already been added. Multiple calls passing the same combination of eventName and listener will result in the listener being added, and called, multiple times.

server.on('connection', (stream) => {
  console.log('someone connected!');
});
js

Returns a reference to the EventEmitter, so that calls can be chained.

By default, event listeners are invoked in the order they are added. The emitter.prependListener() method can be used as an alternative to add the event listener to the beginning of the listeners array.

import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
const EventEmitter = require('node:events');
const myEE = new EventEmitter();
myEE.on('foo', () => console.log('a'));
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
javascript

emitter.once(eventName, listener)#

Adds a one-time listener function for the event named eventName. The next time eventName is triggered, this listener is removed and then invoked.

server.once('connection', (stream) => {
  console.log('Ah, we have our first user!');
});
js

Returns a reference to the EventEmitter, so that calls can be chained.

By default, event listeners are invoked in the order they are added. The emitter.prependOnceListener() method can be used as an alternative to add the event listener to the beginning of the listeners array.

import { EventEmitter } from 'node:events';
const myEE = new EventEmitter();
myEE.once('foo', () => console.log('a'));
myEE.prependOnceListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
const EventEmitter = require('node:events');
const myEE = new EventEmitter();
myEE.once('foo', () => console.log('a'));
myEE.prependOnceListener('foo', () => console.log('b'));
myEE.emit('foo');
// Prints:
//   b
//   a
javascript

emitter.prependListener(eventName, listener)#

Adds the listener function to the beginning of the listeners array for the event named eventName. No checks are made to see if the listener has already been added. Multiple calls passing the same combination of eventName and listener will result in the listener being added, and called, multiple times.

server.prependListener('connection', (stream) => {
  console.log('someone connected!');
});
js

Returns a reference to the EventEmitter, so that calls can be chained.

emitter.prependOnceListener(eventName, listener)#

Adds a one-time listener function for the event named eventName to the beginning of the listeners array. The next time eventName is triggered, this listener is removed, and then invoked.

server.prependOnceListener('connection', (stream) => {
  console.log('Ah, we have our first user!');
});
js

Returns a reference to the EventEmitter, so that calls can be chained.

emitter.removeAllListeners([eventName])#

Removes all listeners, or those of the specified eventName.

It is bad practice to remove listeners added elsewhere in the code, particularly when the EventEmitter instance was created by some other component or module (e.g. sockets or file streams).

Returns a reference to the EventEmitter, so that calls can be chained.

emitter.removeListener(eventName, listener)#

Removes the specified listener from the listener array for the event named eventName.

const callback = (stream) => {
  console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
js

removeListener() will remove, at most, one instance of a listener from the listener array. If any single listener has been added multiple times to the listener array for the specified eventName, then removeListener() must be called multiple times to remove each instance.

Once an event is emitted, all listeners attached to it at the time of emitting are called in order. This implies that any removeListener() or removeAllListeners() calls after emitting and before the last listener finishes execution will not remove them from emit() in progress. Subsequent events behave as expected.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

const callbackA = () => {
  console.log('A');
  myEmitter.removeListener('event', callbackB);
};

const callbackB = () => {
  console.log('B');
};

myEmitter.on('event', callbackA);

myEmitter.on('event', callbackB);

// callbackA removes listener callbackB but it will still be called.
// Internal listener array at time of emit [callbackA, callbackB]
myEmitter.emit('event');
// Prints:
//   A
//   B

// callbackB is now removed.
// Internal listener array [callbackA]
myEmitter.emit('event');
// Prints:
//   A
const EventEmitter = require('node:events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

const callbackA = () => {
  console.log('A');
  myEmitter.removeListener('event', callbackB);
};

const callbackB = () => {
  console.log('B');
};

myEmitter.on('event', callbackA);

myEmitter.on('event', callbackB);

// callbackA removes listener callbackB but it will still be called.
// Internal listener array at time of emit [callbackA, callbackB]
myEmitter.emit('event');
// Prints:
//   A
//   B

// callbackB is now removed.
// Internal listener array [callbackA]
myEmitter.emit('event');
// Prints:
//   A
javascript

Because listeners are managed using an internal array, calling this will change the position indexes of any listener registered after the listener being removed. This will not impact the order in which listeners are called, but it means that any copies of the listener array as returned by the emitter.listeners() method will need to be recreated.

When a single function has been added as a handler multiple times for a single event (as in the example below), removeListener() will remove the most recently added instance. In the example the once('ping') listener is removed:

import { EventEmitter } from 'node:events';
const ee = new EventEmitter();

function pong() {
  console.log('pong');
}

ee.on('ping', pong);
ee.once('ping', pong);
ee.removeListener('ping', pong);

ee.emit('ping');
ee.emit('ping');
const EventEmitter = require('node:events');
const ee = new EventEmitter();

function pong() {
  console.log('pong');
}

ee.on('ping', pong);
ee.once('ping', pong);
ee.removeListener('ping', pong);

ee.emit('ping');
ee.emit('ping');
javascript

Returns a reference to the EventEmitter, so that calls can be chained.

emitter.setMaxListeners(n)#

By default EventEmitters will print a warning if more than 10 listeners are added for a particular event. This is a useful default that helps finding memory leaks. The emitter.setMaxListeners() method allows the limit to be modified for this specific EventEmitter instance. The value can be set to Infinity (or 0) to indicate an unlimited number of listeners.

Returns a reference to the EventEmitter, so that calls can be chained.

emitter.rawListeners(eventName)#

Returns a copy of the array of listeners for the event named eventName, including any wrappers (such as those created by .once()).

import { EventEmitter } from 'node:events';
const emitter = new EventEmitter();
emitter.once('log', () => console.log('log once'));

// Returns a new Array with a function `onceWrapper` which has a property
// `listener` which contains the original listener bound above
const listeners = emitter.rawListeners('log');
const logFnWrapper = listeners[0];

// Logs "log once" to the console and does not unbind the `once` event
logFnWrapper.listener();

// Logs "log once" to the console and removes the listener
logFnWrapper();

emitter.on('log', () => console.log('log persistently'));
// Will return a new Array with a single function bound by `.on()` above
const newListeners = emitter.rawListeners('log');

// Logs "log persistently" twice
newListeners[0]();
emitter.emit('log');
const EventEmitter = require('node:events');
const emitter = new EventEmitter();
emitter.once('log', () => console.log('log once'));

// Returns a new Array with a function `onceWrapper` which has a property
// `listener` which contains the original listener bound above
const listeners = emitter.rawListeners('log');
const logFnWrapper = listeners[0];

// Logs "log once" to the console and does not unbind the `once` event
logFnWrapper.listener();

// Logs "log once" to the console and removes the listener
logFnWrapper();

emitter.on('log', () => console.log('log persistently'));
// Will return a new Array with a single function bound by `.on()` above
const newListeners = emitter.rawListeners('log');

// Logs "log persistently" twice
newListeners[0]();
emitter.emit('log');
javascript

emitter[Symbol.for('nodejs.rejection')](err, eventName[, ...args])#

The Symbol.for('nodejs.rejection') method is called in case a promise rejection happens when emitting an event and captureRejections is enabled on the emitter. It is possible to use events.captureRejectionSymbol in place of Symbol.for('nodejs.rejection').

import { EventEmitter, captureRejectionSymbol } from 'node:events';

class MyClass extends EventEmitter {
  constructor() {
    super({ captureRejections: true });
  }

  [captureRejectionSymbol](err, event, ...args) {
    console.log('rejection happened for', event, 'with', err, ...args);
    this.destroy(err);
  }

  destroy(err) {
    // Tear the resource down here.
  }
}
const { EventEmitter, captureRejectionSymbol } = require('node:events');

class MyClass extends EventEmitter {
  constructor() {
    super({ captureRejections: true });
  }

  [captureRejectionSymbol](err, event, ...args) {
    console.log('rejection happened for', event, 'with', err, ...args);
    this.destroy(err);
  }

  destroy(err) {
    // Tear the resource down here.
  }
}
javascript

events.defaultMaxListeners#

By default, a maximum of 10 listeners can be registered for any single event. This limit can be changed for individual EventEmitter instances using the emitter.setMaxListeners(n) method. To change the default for all EventEmitter instances, the events.defaultMaxListeners property can be used. If this value is not a positive number, a RangeError is thrown.

Take caution when setting the events.defaultMaxListeners because the change affects all EventEmitter instances, including those created before the change is made. However, calling emitter.setMaxListeners(n) still has precedence over events.defaultMaxListeners.

This is not a hard limit. The EventEmitter instance will allow more listeners to be added but will output a trace warning to stderr indicating that a "possible EventEmitter memory leak" has been detected. For any single EventEmitter, the emitter.getMaxListeners() and emitter.setMaxListeners() methods can be used to temporarily avoid this warning:

defaultMaxListeners has no effect on AbortSignal instances. While it is still possible to use emitter.setMaxListeners(n) to set a warning limit for individual AbortSignal instances, per default AbortSignal instances will not warn.

import { EventEmitter } from 'node:events';
const emitter = new EventEmitter();
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
  // do stuff
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
const EventEmitter = require('node:events');
const emitter = new EventEmitter();
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
  // do stuff
  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
javascript

The --trace-warnings command-line flag can be used to display the stack trace for such warnings.

The emitted warning can be inspected with process.on('warning') and will have the additional emitter, type, and count properties, referring to the event emitter instance, the event's name and the number of attached listeners, respectively. Its name property is set to 'MaxListenersExceededWarning'.

events.errorMonitor#

This symbol shall be used to install a listener for only monitoring 'error' events. Listeners installed using this symbol are called before the regular 'error' listeners are called.

Installing a listener using this symbol does not change the behavior once an 'error' event is emitted. Therefore, the process will still crash if no regular 'error' listener is installed.

events.getEventListeners(emitterOrTarget, eventName)#

Returns a copy of the array of listeners for the event named eventName.

For EventEmitters this behaves exactly the same as calling .listeners on the emitter.

For EventTargets this is the only way to get the event listeners for the event target. This is useful for debugging and diagnostic purposes.

import { getEventListeners, EventEmitter } from 'node:events';

{
  const ee = new EventEmitter();
  const listener = () => console.log('Events are fun');
  ee.on('foo', listener);
  console.log(getEventListeners(ee, 'foo')); // [ [Function: listener] ]
}
{
  const et = new EventTarget();
  const listener = () => console.log('Events are fun');
  et.addEventListener('foo', listener);
  console.log(getEventListeners(et, 'foo')); // [ [Function: listener] ]
}
const { getEventListeners, EventEmitter } = require('node:events');

{
  const ee = new EventEmitter();
  const listener = () => console.log('Events are fun');
  ee.on('foo', listener);
  console.log(getEventListeners(ee, 'foo')); // [ [Function: listener] ]
}
{
  const et = new EventTarget();
  const listener = () => console.log('Events are fun');
  et.addEventListener('foo', listener);
  console.log(getEventListeners(et, 'foo')); // [ [Function: listener] ]
}
javascript

events.getMaxListeners(emitterOrTarget)#

Returns the currently set max amount of listeners.

For EventEmitters this behaves exactly the same as calling .getMaxListeners on the emitter.

For EventTargets this is the only way to get the max event listeners for the event target. If the number of event handlers on a single EventTarget exceeds the max set, the EventTarget will print a warning.

import { getMaxListeners, setMaxListeners, EventEmitter } from 'node:events';

{
  const ee = new EventEmitter();
  console.log(getMaxListeners(ee)); // 10
  setMaxListeners(11, ee);
  console.log(getMaxListeners(ee)); // 11
}
{
  const et = new EventTarget();
  console.log(getMaxListeners(et)); // 10
  setMaxListeners(11, et);
  console.log(getMaxListeners(et)); // 11
}
const { getMaxListeners, setMaxListeners, EventEmitter } = require('node:events');

{
  const ee = new EventEmitter();
  console.log(getMaxListeners(ee)); // 10
  setMaxListeners(11, ee);
  console.log(getMaxListeners(ee)); // 11
}
{
  const et = new EventTarget();
  console.log(getMaxListeners(et)); // 10
  setMaxListeners(11, et);
  console.log(getMaxListeners(et)); // 11
}
javascript

events.once(emitter, name[, options])#

Creates a Promise that is fulfilled when the EventEmitter emits the given event or that is rejected if the EventEmitter emits 'error' while waiting. The Promise will resolve with an array of all the arguments emitted to the given event.

This method is intentionally generic and works with the web platform EventTarget interface, which has no special 'error' event semantics and does not listen to the 'error' event.

import { once, EventEmitter } from 'node:events';
import process from 'node:process';

const ee = new EventEmitter();

process.nextTick(() => {
  ee.emit('myevent', 42);
});

const [value] = await once(ee, 'myevent');
console.log(value);

const err = new Error('kaboom');
process.nextTick(() => {
  ee.emit('error', err);
});

try {
  await once(ee, 'myevent');
} catch (err) {
  console.error('error happened', err);
}
const { once, EventEmitter } = require('node:events');

async function run() {
  const ee = new EventEmitter();

  process.nextTick(() => {
    ee.emit('myevent', 42);
  });

  const [value] = await once(ee, 'myevent');
  console.log(value);

  const err = new Error('kaboom');
  process.nextTick(() => {
    ee.emit('error', err);
  });

  try {
    await once(ee, 'myevent');
  } catch (err) {
    console.error('error happened', err);
  }
}

run();
javascript

The special handling of the 'error' event is only used when events.once() is used to wait for another event. If events.once() is used to wait for the 'error' event itself, then it is treated as any other kind of event without special handling:

import { EventEmitter, once } from 'node:events';

const ee = new EventEmitter();

once(ee, 'error')
  .then(([err]) => console.log('ok', err.message))
  .catch((err) => console.error('error', err.message));

ee.emit('error', new Error('boom'));

// Prints: ok boom
const { EventEmitter, once } = require('node:events');

const ee = new EventEmitter();

once(ee, 'error')
  .then(([err]) => console.log('ok', err.message))
  .catch((err) => console.error('error', err.message));

ee.emit('error', new Error('boom'));

// Prints: ok boom
javascript

An <AbortSignal> can be used to cancel waiting for the event:

import { EventEmitter, once } from 'node:events';

const ee = new EventEmitter();
const ac = new AbortController();

async function foo(emitter, event, signal) {
  try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Waiting for the event was canceled!');
    } else {
      console.error('There was an error', error.message);
    }
  }
}

foo(ee, 'foo', ac.signal);
ac.abort(); // Prints: Waiting for the event was canceled!
const { EventEmitter, once } = require('node:events');

const ee = new EventEmitter();
const ac = new AbortController();

async function foo(emitter, event, signal) {
  try {
    await once(emitter, event, { signal });
    console.log('event emitted!');
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('Waiting for the event was canceled!');
    } else {
      console.error('There was an error', error.message);
    }
  }
}

foo(ee, 'foo', ac.signal);
ac.abort(); // Prints: Waiting for the event was canceled!
javascript

Caveats when awaiting multiple events#

It is important to be aware of execution order when using the events.once() method to await multiple events.

Conventional event listeners are called synchronously when the event is emitted. This guarantees that execution will not proceed beyond the emitted event until all listeners have finished executing.

The same is not true when awaiting Promises returned by events.once(). Promise tasks are not handled until after the current execution stack runs to completion, which means that multiple events could be emitted before asynchronous execution continues from the relevant await statement.

As a result, events can be "missed" if a series of await events.once() statements is used to listen to multiple events, since there might be times where more than one event is emitted during the same phase of the event loop. (The same is true when using process.nextTick() to emit events, because the tasks queued by process.nextTick() are executed before Promise tasks.)

import { EventEmitter, once } from 'node:events';
import process from 'node:process';

const myEE = new EventEmitter();

async function listen() {
  await once(myEE, 'foo');
  console.log('foo');

  // This Promise will never resolve, because the 'bar' event will
  // have already been emitted before the next line is executed.
  await once(myEE, 'bar');
  console.log('bar');
}

process.nextTick(() => {
  myEE.emit('foo');
  myEE.emit('bar');
});

listen().then(() => console.log('done'));
const { EventEmitter, once } = require('node:events');

const myEE = new EventEmitter();

async function listen() {
  await once(myEE, 'foo');
  console.log('foo');

  // This Promise will never resolve, because the 'bar' event will
  // have already been emitted before the next line is executed.
  await once(myEE, 'bar');
  console.log('bar');
}

process.nextTick(() => {
  myEE.emit('foo');
  myEE.emit('bar');
});

listen().then(() => console.log('done'));
javascript

To catch multiple events, create all of the Promises before awaiting any of them. This is usually made easier by using Promise.all(), Promise.race(), or Promise.allSettled():

import { EventEmitter, once } from 'node:events';
import process from 'node:process';

const myEE = new EventEmitter();

async function listen() {
  await Promise.all([
    once(myEE, 'foo'),
    once(myEE, 'bar'),
  ]);
  console.log('foo', 'bar');
}

process.nextTick(() => {
  myEE.emit('foo');
  myEE.emit('bar');
});

listen().then(() => console.log('done'));
const { EventEmitter, once } = require('node:events');

const myEE = new EventEmitter();

async function listen() {
  await Promise.all([
    once(myEE, 'bar'),
    once(myEE, 'foo'),
  ]);
  console.log('foo', 'bar');
}

process.nextTick(() => {
  myEE.emit('foo');
  myEE.emit('bar');
});

listen().then(() => console.log('done'));
javascript

events.captureRejections#

Change the default captureRejections option on all new EventEmitter objects.

events.captureRejectionSymbol#

  • Type: <symbol> Symbol.for('nodejs.rejection')

See how to write a custom rejection handler.

events.listenerCount(emitterOrTarget, eventName)#

Returns the number of registered listeners for the event named eventName.

For EventEmitters this behaves exactly the same as calling .listenerCount on the emitter.

For EventTargets this is the only way to obtain the listener count. This can be useful for debugging and diagnostic purposes.

import { EventEmitter, listenerCount } from 'node:events';

{
  const ee = new EventEmitter();
  ee.on('event', () => {});
  ee.on('event', () => {});
  console.log(listenerCount(ee, 'event')); // 2
}
{
  const et = new EventTarget();
  et.addEventListener('event', () => {});
  et.addEventListener('event', () => {});
  console.log(listenerCount(et, 'event')); // 2
}
const { EventEmitter, listenerCount } = require('node:events');

{
  const ee = new EventEmitter();
  ee.on('event', () => {});
  ee.on('event', () => {});
  console.log(listenerCount(ee, 'event')); // 2
}
{
  const et = new EventTarget();
  et.addEventListener('event', () => {});
  et.addEventListener('event', () => {});
  console.log(listenerCount(et, 'event')); // 2
}
javascript

events.on(emitter, eventName[, options])#

  • emitter <EventEmitter>
  • eventName <string> | <symbol> The name of the event being listened for
  • options <Object>
    • signal <AbortSignal> Can be used to cancel awaiting events.
    • close <string>[] Names of events that will end the iteration.
    • highWaterMark <integer> Default: Number.MAX_SAFE_INTEGER The high watermark. The emitter is paused every time the size of events being buffered is higher than it. Supported only on emitters implementing pause() and resume() methods.
    • lowWaterMark <integer> Default: 1 The low watermark. The emitter is resumed every time the size of events being buffered is lower than it. Supported only on emitters implementing pause() and resume() methods.
  • Returns: <AsyncIterator> that iterates eventName events emitted by the emitter
import { on, EventEmitter } from 'node:events';
import process from 'node:process';

const ee = new EventEmitter();

// Emit later on
process.nextTick(() => {
  ee.emit('foo', 'bar');
  ee.emit('foo', 42);
});

for await (const event of on(ee, 'foo')) {
  // The execution of this inner block is synchronous and it
  // processes one event at a time (even with await). Do not use
  // if concurrent execution is required.
  console.log(event); // prints ['bar'] [42]
}
// Unreachable here
const { on, EventEmitter } = require('node:events');

(async () => {
  const ee = new EventEmitter();

  // Emit later on
  process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
  });

  for await (const event of on(ee, 'foo')) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
  }
  // Unreachable here
})();
javascript

Returns an AsyncIterator that iterates eventName events. It will throw if the EventEmitter emits 'error'. It removes all listeners when exiting the loop. The value returned by each iteration is an array composed of the emitted event arguments.

An <AbortSignal> can be used to cancel waiting on events:

import { on, EventEmitter } from 'node:events';
import process from 'node:process';

const ac = new AbortController();

(async () => {
  const ee = new EventEmitter();

  // Emit later on
  process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
  });

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
  }
  // Unreachable here
})();

process.nextTick(() => ac.abort());
const { on, EventEmitter } = require('node:events');

const ac = new AbortController();

(async () => {
  const ee = new EventEmitter();

  // Emit later on
  process.nextTick(() => {
    ee.emit('foo', 'bar');
    ee.emit('foo', 42);
  });

  for await (const event of on(ee, 'foo', { signal: ac.signal })) {
    // The execution of this inner block is synchronous and it
    // processes one event at a time (even with await). Do not use
    // if concurrent execution is required.
    console.log(event); // prints ['bar'] [42]
  }
  // Unreachable here
})();

process.nextTick(() => ac.abort());
javascript

events.setMaxListeners(n[, ...eventTargets])#

import { setMaxListeners, EventEmitter } from 'node:events';

const target = new EventTarget();
const emitter = new EventEmitter();

setMaxListeners(5, target, emitter);
const {
  setMaxListeners,
  EventEmitter,
} = require('node:events');

const target = new EventTarget();
const emitter = new EventEmitter();

setMaxListeners(5, target, emitter);
javascript

events.addAbortListener(signal, listener)#

Listens once to the abort event on the provided signal.

Listening to the abort event on abort signals is unsafe and may lead to resource leaks since another third party with the signal can call e.stopImmediatePropagation(). Unfortunately Node.js cannot change this since it would violate the web standard. Additionally, the original API makes it easy to forget to remove listeners.

This API allows safely using AbortSignals in Node.js APIs by solving these two issues by listening to the event such that stopImmediatePropagation does not prevent the listener from running.

Returns a disposable so that it may be unsubscribed from more easily.

const { addAbortListener } = require('node:events');

function example(signal) {
  signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
  // addAbortListener() returns a disposable, so the `using` keyword ensures
  // the abort listener is automatically removed when this scope exits.
  using _ = addAbortListener(signal, (e) => {
    // Do something when signal is aborted.
  });
}
import { addAbortListener } from 'node:events';

function example(signal) {
  signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
  // addAbortListener() returns a disposable, so the `using` keyword ensures
  // the abort listener is automatically removed when this scope exits.
  using _ = addAbortListener(signal, (e) => {
    // Do something when signal is aborted.
  });
}
javascript

Class: events.EventEmitterAsyncResource extends EventEmitter#

Integrates EventEmitter with <AsyncResource> for EventEmitters that require manual async tracking. Specifically, all events emitted by instances of events.EventEmitterAsyncResource will run within its async context.

import { EventEmitterAsyncResource, EventEmitter } from 'node:events';
import { notStrictEqual, strictEqual } from 'node:assert';
import { executionAsyncId, triggerAsyncId } from 'node:async_hooks';

// Async tracking tooling will identify this as 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' });

// 'foo' listeners will run in the EventEmitters async context.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId);
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId);
});

const ee2 = new EventEmitter();

// 'foo' listeners on ordinary EventEmitters that do not track async
// context, however, run in the same async context as the emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId);
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId);
});

Promise.resolve().then(() => {
  ee1.emit('foo');
  ee2.emit('foo');
});
const { EventEmitterAsyncResource, EventEmitter } = require('node:events');
const { notStrictEqual, strictEqual } = require('node:assert');
const { executionAsyncId, triggerAsyncId } = require('node:async_hooks');

// Async tracking tooling will identify this as 'Q'.
const ee1 = new EventEmitterAsyncResource({ name: 'Q' });

// 'foo' listeners will run in the EventEmitters async context.
ee1.on('foo', () => {
  strictEqual(executionAsyncId(), ee1.asyncId);
  strictEqual(triggerAsyncId(), ee1.triggerAsyncId);
});

const ee2 = new EventEmitter();

// 'foo' listeners on ordinary EventEmitters that do not track async
// context, however, run in the same async context as the emit().
ee2.on('foo', () => {
  notStrictEqual(executionAsyncId(), ee2.asyncId);
  notStrictEqual(triggerAsyncId(), ee2.triggerAsyncId);
});

Promise.resolve().then(() => {
  ee1.emit('foo');
  ee2.emit('foo');
});
javascript

The EventEmitterAsyncResource class has the same methods and takes the same options as EventEmitter and AsyncResource themselves.

new events.EventEmitterAsyncResource([options])#

  • options <Object>
    • captureRejections <boolean> It enables automatic capturing of promise rejection. Default: false.
    • name <string> The type of async event. Default: new.target.name.
    • triggerAsyncId <number> The ID of the execution context that created this async event. Default: executionAsyncId().
    • requireManualDestroy <boolean> If set to true, disables emitDestroy when the object is garbage collected. This usually does not need to be set (even if emitDestroy is called manually), unless the resource's asyncId is retrieved and the sensitive API's emitDestroy is called with it. When set to false, the emitDestroy call on garbage collection will only take place if there is at least one active destroy hook. Default: false.

eventemitterasyncresource.asyncId#

  • Type: <number> The unique asyncId assigned to the resource.

eventemitterasyncresource.asyncResource#

The returned AsyncResource object has an additional eventEmitter property that provides a reference to this EventEmitterAsyncResource.

eventemitterasyncresource.emitDestroy()#

Call all destroy hooks. This should only ever be called once. An error will be thrown if it is called more than once. This must be manually called. If the resource is left to be collected by the GC then the destroy hooks will never be called.

eventemitterasyncresource.triggerAsyncId#

  • Type: <number> The same triggerAsyncId that is passed to the AsyncResource constructor.

EventTarget and Event API#

The EventTarget and Event objects are a Node.js-specific implementation of the EventTarget Web API that are exposed by some Node.js core APIs.

const target = new EventTarget();

target.addEventListener('foo', (event) => {
  console.log('foo event happened!');
});
js

Node.js EventTarget vs. DOM EventTarget#

There are two key differences between the Node.js EventTarget and the EventTarget Web API:

  1. Whereas DOM EventTarget instances may be hierarchical, there is no concept of hierarchy and event propagation in Node.js. That is, an event dispatched to an EventTarget does not propagate through a hierarchy of nested target objects that may each have their own set of handlers for the event.
  2. In the Node.js EventTarget, if an event listener is an async function or returns a Promise, and the returned Promise rejects, the rejection is automatically captured and handled the same way as a listener that throws synchronously (see EventTarget error handling for details).

NodeEventTarget vs. EventEmitter#

The NodeEventTarget object implements a modified subset of the EventEmitter API that allows it to closely emulate an EventEmitter in certain situations. A NodeEventTarget is not an instance of EventEmitter and cannot be used in place of an EventEmitter in most cases.

  1. Unlike EventEmitter, any given listener can be registered at most once per event type. Attempts to register a listener multiple times are ignored.
  2. The NodeEventTarget does not emulate the full EventEmitter API. Specifically the prependListener(), prependOnceListener(), rawListeners(), and errorMonitor APIs are not emulated. The 'newListener' and 'removeListener' events will also not be emitted.
  3. The NodeEventTarget does not implement any special default behavior for events with type 'error'.
  4. The NodeEventTarget supports EventListener objects as well as functions as handlers for all event types.

Event listener#

Event listeners registered for an event type may either be JavaScript functions or objects with a handleEvent property whose value is a function.

In either case, the handler function is invoked with the event argument passed to the eventTarget.dispatchEvent() function.

Async functions may be used as event listeners. If an async handler function rejects, the rejection is captured and handled as described in EventTarget error handling.

An error thrown by one handler function does not prevent the other handlers from being invoked.

The return value of a handler function is ignored.

Handlers are always invoked in the order they were added.

Handler functions may mutate the event object.

function handler1(event) {
  console.log(event.type);  // Prints 'foo'
  event.a = 1;
}

async function handler2(event) {
  console.log(event.type);  // Prints 'foo'
  console.log(event.a);  // Prints 1
}

const handler3 = {
  handleEvent(event) {
    console.log(event.type);  // Prints 'foo'
  },
};

const handler4 = {
  async handleEvent(event) {
    console.log(event.type);  // Prints 'foo'
  },
};

const target = new EventTarget();

target.addEventListener('foo', handler1);
target.addEventListener('foo', handler2);
target.addEventListener('foo', handler3);
target.addEventListener('foo', handler4, { once: true });
js

EventTarget error handling#

When a registered event listener throws (or returns a Promise that rejects), by default the error is treated as an uncaught exception on process.nextTick(). This means uncaught exceptions in EventTargets will terminate the Node.js process by default.

Throwing within an event listener will not stop the other registered handlers from being invoked.

The EventTarget does not implement any special default handling for 'error' type events like EventEmitter.

Currently errors are first forwarded to the process.on('error') event before reaching process.on('uncaughtException'). This behavior is deprecated and will change in a future release to align EventTarget with other Node.js APIs. Any code relying on the process.on('error') event should be aligned with the new behavior.

Class: Event#

The Event object is an adaptation of the Event Web API. Instances are created internally by Node.js.

event.bubbles#

This is not used in Node.js and is provided purely for completeness.

event.cancelBubble#

Stability: 3 - Legacy: Use event.stopPropagation() instead.

Alias for event.stopPropagation() if set to true. This is not used in Node.js and is provided purely for completeness.

event.cancelable#
  • Type: <boolean> True if the event was created with the cancelable option.
event.composed#

This is not used in Node.js and is provided purely for completeness.

event.composedPath()#

Returns an array containing the current EventTarget as the only entry or empty if the event is not being dispatched. This is not used in Node.js and is provided purely for completeness.

event.currentTarget#

Alias for event.target.

event.defaultPrevented#

Is true if cancelable is true and event.preventDefault() has been called.

event.eventPhase#
  • Type: <number> Returns 0 while an event is not being dispatched, 2 while it is being dispatched.

This is not used in Node.js and is provided purely for completeness.

event.initEvent(type[, bubbles[, cancelable]])#

Stability: 3 - Legacy: The WHATWG spec considers it deprecated and users shouldn't use it at all.

Redundant with event constructors and incapable of setting composed. This is not used in Node.js and is provided purely for completeness.

event.isTrusted#

The <AbortSignal> "abort" event is emitted with isTrusted set to true. The value is false in all other cases.

event.preventDefault()#

Sets the defaultPrevented property to true if cancelable is true.

event.returnValue#

Stability: 3 - Legacy: Use event.defaultPrevented instead.

  • Type: <boolean> True if the event has not been canceled.

The value of event.returnValue is always the opposite of event.defaultPrevented. This is not used in Node.js and is provided purely for completeness.

event.srcElement#

Stability: 3 - Legacy: Use event.target instead.

Alias for event.target.

event.stopImmediatePropagation()#

Stops the invocation of event listeners after the current one completes.

event.stopPropagation()#

This is not used in Node.js and is provided purely for completeness.

event.target#
event.timeStamp#

The millisecond timestamp when the Event object was created.

event.type#

The event type identifier.

Class: EventTarget#

eventTarget.addEventListener(type, listener[, options])#
  • type <string>
  • listener <Function> | <EventListener>
  • options <Object>
    • once <boolean> When true, the listener is automatically removed when it is first invoked. Default: false.
    • passive <boolean> When true, serves as a hint that the listener will not call the Event object's preventDefault() method. Default: false.
    • capture <boolean> Not directly used by Node.js. Added for API completeness. Default: false.
    • signal <AbortSignal> The listener will be removed when the given AbortSignal object's abort() method is called.

Adds a new handler for the type event. Any given listener is added only once per type and per capture option value.

If the once option is true, the listener is removed after the next time a type event is dispatched.

The capture option is not used by Node.js in any functional way other than tracking registered event listeners per the EventTarget specification. Specifically, the capture option is used as part of the key when registering a listener. Any individual listener may be added once with capture = false, and once with capture = true.

function handler(event) {}

const target = new EventTarget();
target.addEventListener('foo', handler, { capture: true });  // first
target.addEventListener('foo', handler, { capture: false }); // second

// Removes the second instance of handler
target.removeEventListener('foo', handler);

// Removes the first instance of handler
target.removeEventListener('foo', handler, { capture: true });
js
eventTarget.dispatchEvent(event)#
  • event <Event>
  • Returns: <boolean> true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, otherwise false.

Dispatches the event to the list of handlers for event.type.

The registered event listeners is synchronously invoked in the order they were registered.

eventTarget.removeEventListener(type, listener[, options])#

Removes the listener from the list of handlers for event type.

Class: CustomEvent#

The CustomEvent object is an adaptation of the CustomEvent Web API. Instances are created internally by Node.js.

event.detail#
  • Type: <any> Returns custom data passed when initializing.

Read-only.

Class: NodeEventTarget#

The NodeEventTarget is a Node.js-specific extension to EventTarget that emulates a subset of the EventEmitter API.

nodeEventTarget.addListener(type, listener)#

Node.js-specific extension to the EventTarget class that emulates the equivalent EventEmitter API. The only difference between addListener() and addEventListener() is that addListener() will return a reference to the EventTarget.

nodeEventTarget.emit(type, arg)#
  • type <string>
  • arg <any>
  • Returns: <boolean> true if event listeners registered for the type exist, otherwise false.

Node.js-specific extension to the EventTarget class that dispatches the arg to the list of handlers for type.

nodeEventTarget.eventNames()#

Node.js-specific extension to the EventTarget class that returns an array of event type names for which event listeners are registered.

nodeEventTarget.listenerCount(type)#

Node.js-specific extension to the EventTarget class that returns the number of event listeners registered for the type.

nodeEventTarget.setMaxListeners(n)#

Node.js-specific extension to the EventTarget class that sets the number of max event listeners as n.

nodeEventTarget.getMaxListeners()#

Node.js-specific extension to the EventTarget class that returns the number of max event listeners.

nodeEventTarget.off(type, listener[, options])#

Node.js-specific alias for eventTarget.removeEventListener().

nodeEventTarget.on(type, listener)#

Node.js-specific alias for eventTarget.addEventListener().

nodeEventTarget.once(type, listener)#

Node.js-specific extension to the EventTarget class that adds a once listener for the given event type. This is equivalent to calling on with the once option set to true.

nodeEventTarget.removeAllListeners([type])#

Node.js-specific extension to the EventTarget class. If type is specified, removes all registered listeners for type, otherwise removes all registered listeners.

nodeEventTarget.removeListener(type, listener[, options])#

Node.js-specific extension to the EventTarget class that removes the listener for the given type. The only difference between removeListener() and removeEventListener() is that removeListener() will return a reference to the EventTarget.

FFI#

Stability: 1 - Experimental

The node:ffi module provides an experimental foreign function interface for loading dynamic libraries and calling native symbols from JavaScript.

This API is unsafe. Passing invalid pointers, using an incorrect symbol signature, or accessing memory after it has been freed can crash the process or corrupt memory.

To access it:

import ffi from 'node:ffi';
const ffi = require('node:ffi');
javascript

This module is only available under the node: scheme in builds with FFI support and is gated by the --experimental-ffi flag.

Building Node.js with node:ffi support is available via the bundled libffi on platforms where libffi provides a compatible static backend, or via a shared libffi using the --shared-ffi configure flag. The unofficial GN build does not support node:ffi.

The following targets are not supported by bundled libffi:

  • s390x.
  • mips, mipsel, and mips64el on targets other than FreeBSD, Linux, and OpenBSD.
  • ppc64 on Android, CloudABI, iOS, OpenHarmony, OS/400, Solaris, and Windows.

When using the Permission Model, FFI APIs are restricted unless the --allow-ffi flag is provided.

Overview#

The node:ffi module exposes two groups of APIs:

  • Dynamic library APIs for loading libraries, resolving symbols, and creating callable JavaScript wrappers.
  • Raw memory helpers for reading and writing primitive values through pointers, converting pointers to JavaScript strings, Buffer instances, and ArrayBuffer instances, and for copying data back into native memory.

Type names#

FFI signatures use string type names.

Supported type names:

  • void
  • char
  • i8, int8
  • u8, uint8, bool
  • i16, int16
  • u16, uint16
  • i32, int32
  • u32, uint32
  • i64, int64
  • u64, uint64
  • f32, float, float32
  • f64, double, float64
  • pointer, ptr
  • string, str
  • buffer
  • arraybuffer
  • function

These type names are also exposed as constants on ffi.types:

  • ffi.types.VOID = 'void'
  • ffi.types.POINTER = 'pointer'
  • ffi.types.BUFFER = 'buffer'
  • ffi.types.ARRAY_BUFFER = 'arraybuffer'
  • ffi.types.FUNCTION = 'function'
  • ffi.types.BOOL = 'bool'
  • ffi.types.CHAR = 'char'
  • ffi.types.STRING = 'string'
  • ffi.types.FLOAT = 'float'
  • ffi.types.DOUBLE = 'double'
  • ffi.types.INT_8 = 'int8'
  • ffi.types.UINT_8 = 'uint8'
  • ffi.types.INT_16 = 'int16'
  • ffi.types.UINT_16 = 'uint16'
  • ffi.types.INT_32 = 'int32'
  • ffi.types.UINT_32 = 'uint32'
  • ffi.types.INT_64 = 'int64'
  • ffi.types.UINT_64 = 'uint64'
  • ffi.types.FLOAT_32 = 'float32'
  • ffi.types.FLOAT_64 = 'float64'

Pointer-like types (pointer, string, buffer, arraybuffer, and function) are all passed through the native layer as pointers.

When Buffer, ArrayBuffer, or typed array values are passed as pointer-like arguments, Node.js borrows a raw pointer to their backing memory for the duration of the native call. The caller must ensure that backing store remains valid and stable for the entire call.

It is unsupported and dangerous to resize, transfer, detach, or otherwise invalidate that backing store while the native call is active, including through reentrant JavaScript such as FFI callbacks. Doing so may crash the process, produce incorrect output, or corrupt memory.

The char type follows the platform C ABI. On platforms where plain C char is signed it behaves like i8; otherwise it behaves like u8.

The bool type is marshaled as an 8-bit unsigned integer. Pass numeric values such as 0 and 1; JavaScript true and false are not accepted.

On optimized Fast FFI calls, pointer, ptr, and function parameters accept raw pointer bigint values. For pointer-like parameters, null, undefined, strings, Buffer, typed array, DataView, and ArrayBuffer values are converted on the JavaScript side before calling the optimized native wrapper.

Optimized Fast FFI calls support at most 8 function arguments, but the exact limit depends on the architecture and on the argument types, because each argument must fit in the registers used by the platform trampoline. Integer and pointer arguments are limited to 7 on AArch64 and to 6 on x86-64, while floating-point arguments can use up to 8 on both. Functions that exceed these limits, including any function with more than 8 arguments, use the generic FFI call path instead.

Signature objects#

Functions and callbacks are described with signature objects.

Signature objects may contain the following properties, both of which are optional:

  • return <string>type name specifying the return type of the function or callback. Default: 'void'.
  • arguments <string>[] An array of type names specifying the argument type list of the function or callback. Default: [].
const signature = {
  return: 'i32',
  arguments: ['i32', 'i32'],
};
js

ffi.suffix#

The native shared library suffix for the current platform:

  • 'dylib' on macOS
  • 'so' on Unix-like platforms
  • 'dll' on Windows

This can be used to build portable library paths:

const { suffix } = require('node:ffi');

const path = `libsqlite3.${suffix}`;
cjs

ffi.dlopen(path[, definitions])#

  • path <string> | <null> Path to a dynamic library, or null to resolve symbols from the current process image.
  • definitions <Object> Symbol definitions to resolve immediately.
  • Returns: <Object>

Loads a dynamic library and resolves the requested function definitions.

On Windows passing null is not supported.

When definitions is omitted, functions is returned as an empty object until symbols are resolved explicitly.

The returned object contains:

The returned object also implements the explicit resource management protocol, so it can be used with the using declaration. Disposing the returned object closes the library handle.

import { dlopen, suffix } from 'node:ffi';

{
  using handle = dlopen(`./mylib.${suffix}`, {
    add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
  });
  console.log(handle.functions.add_i32(20, 22));
} // handle.lib.close() is invoked automatically here.
mjs
import { dlopen, suffix } from 'node:ffi';

const { lib, functions } = dlopen(`./mylib.${suffix}`, {
  add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
  string_length: { arguments: ['pointer'], return: 'u64' },
});

console.log(functions.add_i32(20, 22));
const { dlopen, suffix } = require('node:ffi');

const { lib, functions } = dlopen(`./mylib.${suffix}`, {
  add_i32: { arguments: ['i32', 'i32'], return: 'i32' },
  string_length: { arguments: ['pointer'], return: 'u64' },
});

console.log(functions.add_i32(20, 22));
javascript

ffi.dlclose(handle)#

Closes a dynamic library.

This is equivalent to calling handle.close().

ffi.dlsym(handle, symbol)#

Resolves a symbol address from a loaded library.

This is equivalent to calling handle.getSymbol(symbol).

Class: DynamicLibrary#

Represents a loaded dynamic library.

new DynamicLibrary(path)#

  • path <string> | <null> Path to a dynamic library, or null to resolve symbols from the current process image.

Loads the dynamic library without resolving any functions eagerly.

On Windows passing null is not supported.

const { DynamicLibrary, suffix } = require('node:ffi');

const lib = new DynamicLibrary(`./mylib.${suffix}`);
cjs

library.path#

The path used to load the library.

library.functions#

An object containing previously resolved function wrappers.

library.symbols#

An object containing previously resolved symbol addresses as bigint values.

library.close()#

Closes the library handle.

DynamicLibrary implements the explicit resource management protocol, so a library instance can be managed with the using declaration. Leaving the enclosing scope invokes library.close() automatically.

import { DynamicLibrary, suffix } from 'node:ffi';

{
  using lib = new DynamicLibrary(`./mylib.${suffix}`);
  // Use `lib` here; `lib.close()` is called when the block exits.
}
mjs

Calling library.close() (or disposing the library) more than once is a no-op.

After a library has been closed:

  • Resolved function wrappers become invalid.
  • Further symbol and function resolution throws.
  • Registered callbacks are invalidated.

Closing a library does not make previously exported callback pointers safe to reuse. Node.js does not track or revoke callback pointers that have already been handed to native code.

If native code still holds a callback pointer after library.close() or after library.unregisterCallback(pointer), invoking that pointer has undefined behavior, is not allowed, and is dangerous: it can crash the process, produce incorrect output, or corrupt memory. Native code must stop using callback addresses before the library is closed or before the callback is unregistered.

Calling library.close() from one of the library's active callbacks is unsupported and dangerous. The callback must return before the library is closed.

library[Symbol.dispose]()#

Calls library.close(). This allows DynamicLibrary instances to be used with the using declaration for automatic cleanup when the enclosing scope exits. It is a no-op on a library that has already been closed.

library.getFunction(name, signature)#

Resolves a symbol and returns a callable JavaScript wrapper.

The returned function has a .pointer property containing the native function address as a bigint.

If the same symbol has already been resolved, requesting it again with a different signature throws.

const { DynamicLibrary, suffix } = require('node:ffi');

const lib = new DynamicLibrary(`./mylib.${suffix}`);
const add = lib.getFunction('add_i32', {
  arguments: ['i32', 'i32'],
  return: 'i32',
});

console.log(add(20, 22));
console.log(add.pointer);
cjs

library.getFunctions([definitions])#

When definitions is provided, resolves each named symbol and returns an object containing callable wrappers.

When definitions is omitted, returns wrappers for all functions that have already been resolved on the library.

library.getSymbol(name)#

Resolves a symbol and returns its native address as a bigint.

library.getSymbols()#

Returns an object containing all previously resolved symbol addresses.

library.registerCallback([signature,] callback)#

Creates a native callback pointer backed by a JavaScript function.

When signature is omitted, the callback uses a default void () signature.

The return value is the callback pointer address as a bigint. It can be passed to native functions expecting a callback pointer.

const { DynamicLibrary, suffix } = require('node:ffi');

const lib = new DynamicLibrary(`./mylib.${suffix}`);

const callback = lib.registerCallback(
  { arguments: ['i32'], return: 'i32' },
  (value) => value * 2,
);
cjs

Callbacks are subject to the following restrictions:

  • They must be invoked on the same system thread where they were created.
  • They must not throw exceptions.
  • They must not return promises.
  • They must return a value compatible with the declared return type.
  • They must not call library.close() on their owning library while running.
  • They must not unregister themselves while running.

Closing the owning library or unregistering the currently executing callback from inside the callback is unsupported and dangerous. Doing so may crash the process, produce incorrect output, or corrupt memory.

library.unregisterCallback(pointer)#

Releases a callback previously created with library.registerCallback().

Calling library.unregisterCallback(pointer) for a callback that is currently executing is unsupported and dangerous. The callback must return before it is unregistered.

After library.unregisterCallback(pointer) returns, invoking that callback pointer from native code has undefined behavior, is not allowed, and is dangerous: it can crash the process, produce incorrect output, or corrupt memory.

library.refCallback(pointer)#

Keeps the callback strongly referenced by JavaScript.

Throws ERR_INVALID_ARG_VALUE if the callback function has already been garbage collected after a previous library.unrefCallback(pointer) call, since a collected function cannot be referenced again.

library.unrefCallback(pointer)#

Allows the callback to become weakly referenced by JavaScript.

If the callback function is later garbage collected, subsequent native invocations become a no-op. Non-void return values are zero-initialized before returning to native code.

Throws ERR_INVALID_ARG_VALUE if the callback function has already been garbage collected.

Calling native functions#

Argument conversion depends on the declared FFI type.

For 8-, 16-, and 32-bit integer types and for floating-point types, pass JavaScript number values that match the declared type.

For 64-bit integer types (i64 and u64), pass JavaScript bigint values.

For pointer-like arguments:

  • null and undefined are passed as null pointers.
  • string values are copied to temporary NUL-terminated UTF-8 strings for the duration of the call.
  • Buffer, typed arrays, and DataView instances pass a pointer to their backing memory.
  • ArrayBuffer passes a pointer to its backing memory.
  • bigint values are passed as raw pointer addresses.

Pointer return values are exposed as bigint addresses.

Primitive memory access helpers#

The following helpers read and write primitive values at a native pointer, optionally with a byte offset:

  • ffi.getInt8(pointer[, offset])
  • ffi.getUint8(pointer[, offset])
  • ffi.getInt16(pointer[, offset])
  • ffi.getUint16(pointer[, offset])
  • ffi.getInt32(pointer[, offset])
  • ffi.getUint32(pointer[, offset])
  • ffi.getInt64(pointer[, offset])
  • ffi.getUint64(pointer[, offset])
  • ffi.getFloat32(pointer[, offset])
  • ffi.getFloat64(pointer[, offset])
  • ffi.setInt8(pointer, offset, value)
  • ffi.setUint8(pointer, offset, value)
  • ffi.setInt16(pointer, offset, value)
  • ffi.setUint16(pointer, offset, value)
  • ffi.setInt32(pointer, offset, value)
  • ffi.setUint32(pointer, offset, value)
  • ffi.setInt64(pointer, offset, value)
  • ffi.setUint64(pointer, offset, value)
  • ffi.setFloat32(pointer, offset, value)
  • ffi.setFloat64(pointer, offset, value)

These helpers perform direct memory reads and writes. pointer must be a bigint referring to valid readable or writable native memory. offset, when provided, is interpreted as a byte offset from pointer.

The getter helpers return JavaScript number values for 8-, 16-, and 32-bit integer types and for floating-point types. They return bigint values for 64-bit integer types.

The setter helpers require an explicit byte offset and validate the supplied JavaScript value against the target native type before writing it into memory. For setInt64() and setUint64(), bigint values are accepted directly; numeric inputs must be integers within JavaScript's safe integer range.

const {
  getInt32,
  setInt32,
} = require('node:ffi');

setInt32(ptr, 0, 42);
console.log(getInt32(ptr, 0));
cjs

Like the other raw memory helpers in this module, these APIs do not track ownership, bounds, or lifetime. Passing an invalid pointer, using the wrong offset, or writing through a stale pointer can corrupt memory or crash the process.

ffi.toString(pointer)#

Reads a NUL-terminated UTF-8 string from native memory.

If pointer is 0n, null is returned.

This function does not validate that pointer refers to readable memory or that the pointed-to data is terminated with \0. Passing an invalid pointer, a pointer to freed memory, or a pointer to bytes without a terminating NUL can read unrelated memory, crash the process, or produce truncated or garbled output.

const { toString } = require('node:ffi');

const value = toString(ptr);
cjs

ffi.toBuffer(pointer, length[, copy])#

Creates a Buffer from native memory.

When copy is true, the returned Buffer owns its own copied memory. When copy is false, the returned Buffer references the original native memory directly.

Using copy: false is a zero-copy escape hatch. The returned Buffer is a writable view onto foreign memory, so writes in JavaScript update the original native memory directly. The caller must guarantee that:

  • pointer remains valid for the entire lifetime of the returned Buffer.
  • length stays within the allocated native region.
  • no native code frees or repurposes that memory while JavaScript still uses the Buffer.
  • Memory protection is observed. For example, read-only memory pages must not be written to.

If these guarantees are not met, reading or writing the Buffer can corrupt memory or crash the process.

ffi.toArrayBuffer(pointer, length[, copy])#

Creates an ArrayBuffer from native memory.

When copy is true, the returned ArrayBuffer contains copied bytes. When copy is false, the returned ArrayBuffer references the original native memory directly.

The same lifetime and bounds requirements described for ffi.toBuffer(pointer, length, copy) apply here. With copy: false, the returned ArrayBuffer is a zero-copy view of foreign memory and is only safe while that memory remains allocated, unchanged in layout, and valid for the entire exposed range.

ffi.exportString(string, pointer, length[, encoding])#

Copies a JavaScript string into native memory and appends a trailing NUL terminator.

length must be large enough to hold the full encoded string plus the trailing NUL terminator. For UTF-16 and UCS-2 encodings, the trailing terminator uses two zero bytes.

pointer must refer to writable native memory with at least length bytes of available storage. This function does not allocate memory on its own.

string must be a JavaScript string. encoding must be a string.

ffi.exportBuffer(buffer, pointer, length)#

Copies bytes from a Buffer into native memory.

length must be at least buffer.length.

pointer must refer to writable native memory with at least length bytes of available storage. This function does not allocate memory on its own.

buffer must be a Node.js Buffer.

ffi.exportArrayBuffer(arrayBuffer, pointer, length)#

Copies bytes from an ArrayBuffer into native memory.

length must be at least arrayBuffer.byteLength.

pointer must refer to writable native memory with at least length bytes of available storage. This function does not allocate memory on its own.

ffi.exportArrayBufferView(arrayBufferView, pointer, length)#

Copies bytes from an ArrayBufferView into native memory.

length must be at least arrayBufferView.byteLength.

pointer must refer to writable native memory with at least length bytes of available storage. This function does not allocate memory on its own.

ffi.getRawPointer(source)#

Returns the raw memory address of JavaScript-managed byte storage.

This is unsafe and dangerous. The returned pointer can become invalid if the underlying memory is detached, resized, transferred, or otherwise invalidated. Using stale pointers can cause memory corruption or process crashes.

ffi.getCurrentEventLoop()#

Returns the address of the current thread's uv_loop_t as a bigint.

The returned address is for the current Node.js environment. In the main thread, this is the main thread event loop. In a worker thread, this is that worker's event loop.

This is unsafe and dangerous. The returned pointer is only valid for the lifetime of the current environment. Using it after the environment exits, or from native code that assumes a different thread or lifetime, can crash the process or corrupt memory.

Safety notes#

The node:ffi module does not track pointer validity, memory ownership, or native object lifetimes.

In particular:

  • Do not read from or write to freed memory.
  • Do not use zero-copy views after the native memory has been released.
  • Do not declare incorrect signatures for native symbols.
  • Do not unregister callbacks while native code may still call them.
  • Do not call callback pointers after library.close() or library.unregisterCallback(pointer).
  • Assume undefined callback behavior can crash the process, produce incorrect output, or corrupt memory.
  • Do not assume pointer return values imply ownership; whether the caller must free the returned address depends entirely on the native API.

As a general rule, prefer copied values unless zero-copy access is required, and keep callback and pointer lifetimes explicit on the native side.

File system#

Stability: 2 - Stable

The node:fs module enables interacting with the file system in a way modeled on standard POSIX functions.

To use the promise-based APIs:

import * as fs from 'node:fs/promises';
const fs = require('node:fs/promises');
javascript

To use the callback and sync APIs:

import * as fs from 'node:fs';
const fs = require('node:fs');
javascript

All file system operations have synchronous, callback, and promise-based forms, and are accessible using both CommonJS syntax and ES6 Modules (ESM).

Promise example#

Promise-based operations return a promise that is fulfilled when the asynchronous operation is complete.

import { unlink } from 'node:fs/promises';

try {
  await unlink('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (error) {
  console.error('there was an error:', error.message);
}
const { unlink } = require('node:fs/promises');

(async function(path) {
  try {
    await unlink(path);
    console.log(`successfully deleted ${path}`);
  } catch (error) {
    console.error('there was an error:', error.message);
  }
})('/tmp/hello');
javascript

Callback example#

The callback form takes a completion callback function as its last argument and invokes the operation asynchronously. The arguments passed to the completion callback depend on the method, but the first argument is always reserved for an exception. If the operation is completed successfully, then the first argument is null or undefined.

import { unlink } from 'node:fs';

unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});
const { unlink } = require('node:fs');

unlink('/tmp/hello', (err) => {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});
javascript

The callback-based versions of the node:fs module APIs are preferable over the use of the promise APIs when maximal performance (both in terms of execution time and memory allocation) is required.

Synchronous example#

The synchronous APIs block the Node.js event loop and further JavaScript execution until the operation is complete. Exceptions are thrown immediately and can be handled using try…catch, or can be allowed to bubble up.

import { unlinkSync } from 'node:fs';

try {
  unlinkSync('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (err) {
  // handle the error
}
const { unlinkSync } = require('node:fs');

try {
  unlinkSync('/tmp/hello');
  console.log('successfully deleted /tmp/hello');
} catch (err) {
  // handle the error
}
javascript

Promises API#

The fs/promises API provides asynchronous file system methods that return promises.

The promise APIs use the underlying Node.js threadpool to perform file system operations off the event loop thread. These operations are not synchronized or threadsafe. Care must be taken when performing multiple concurrent modifications on the same file or data corruption may occur.

Class: FileHandle#

A <FileHandle> object is an object wrapper for a numeric file descriptor.

Instances of the <FileHandle> object are created by the fsPromises.open() method.

All <FileHandle> objects are <EventEmitter>s.

If a <FileHandle> is not closed using the filehandle.close() method, it will try to automatically close the file descriptor and emit a process warning, helping to prevent memory leaks. Please do not rely on this behavior because it can be unreliable and the file may not be closed. Instead, always explicitly close <FileHandle>s. Node.js may change this behavior in the future.

Event: 'close'#

The 'close' event is emitted when the <FileHandle> has been closed and can no longer be used.

filehandle.appendFile(data[, options])#

Alias of filehandle.writeFile().

When operating on file handles, the mode cannot be changed from what it was set to with fsPromises.open(). Therefore, this is equivalent to filehandle.writeFile().

filehandle.chmod(mode)#
  • mode <integer> the file mode bit mask.
  • Returns: <Promise> Fulfills with undefined upon success.

Modifies the permissions on the file. See chmod(2).

filehandle.chown(uid, gid)#
  • uid <integer> The file's new owner's user id.
  • gid <integer> The file's new group's group id.
  • Returns: <Promise> Fulfills with undefined upon success.

Changes the ownership of the file. A wrapper for chown(2).

filehandle.close()#
  • Returns: <Promise> Fulfills with undefined upon success.

Closes the file handle after waiting for any pending operation on the handle to complete.

import { open } from 'node:fs/promises';

let filehandle;
try {
  filehandle = await open('thefile.txt', 'r');
} finally {
  await filehandle?.close();
}
mjs
filehandle.createReadStream([options])#

options can include start and end values to read a range of bytes from the file instead of the entire file. Both start and end are inclusive and start counting at 0, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. If start is omitted or undefined, filehandle.createReadStream() reads sequentially from the current file position. The encoding can be any one of those accepted by <Buffer>.

If the FileHandle points to a character device that only supports blocking reads (such as keyboard or sound card), read operations do not finish until data is available. This can prevent the process from exiting and the stream from closing naturally.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

import { open } from 'node:fs/promises';

const fd = await open('/dev/input/event0');
// Create a stream from some character device.
const stream = fd.createReadStream();
setTimeout(() => {
  stream.close(); // This may not close the stream.
  // Artificially marking end-of-stream, as if the underlying resource had
  // indicated end-of-file by itself, allows the stream to close.
  // This does not cancel pending read operations, and if there is such an
  // operation, the process may still not be able to exit successfully
  // until it finishes.
  stream.push(null);
  stream.read(0);
}, 100);
mjs

If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak. If autoClose is set to true (default behavior), on 'error' or 'end' the file descriptor will be closed automatically.

An example to read the last 10 bytes of a file which is 100 bytes long:

import { open } from 'node:fs/promises';

const fd = await open('sample.txt');
fd.createReadStream({ start: 90, end: 99 });
mjs
filehandle.createWriteStream([options])#

options may also include a start option to allow writing data at some position past the beginning of the file, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. Modifying a file rather than replacing it may require the flags open option to be set to r+ rather than the default r. The encoding can be any one of those accepted by <Buffer>.

If autoClose is set to true (default behavior) on 'error' or 'finish' the file descriptor will be closed automatically. If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

filehandle.datasync()#
  • Returns: <Promise> Fulfills with undefined upon success.

Forces all currently queued I/O operations associated with the file to the operating system's synchronized I/O completion state. Refer to the POSIX fdatasync(2) documentation for details.

Unlike filehandle.sync this method does not flush modified metadata.

filehandle.fd#
filehandle.pull([...transforms][, options])#

Stability: 1 - Experimental

  • ...transforms <Function> | <Object> Optional transforms to apply via stream/iter pull().
  • options <Object>
    • signal <AbortSignal>
    • autoClose <boolean> Close the file handle when the stream ends. Default: false.
    • start <number> Byte offset to begin reading from. When specified, reads use explicit positioning (pread semantics). Default: current file position.
    • limit <number> Maximum number of bytes to read before ending the iterator. Reads stop when limit bytes have been delivered or EOF is reached, whichever comes first. Default: read until EOF.
    • chunkSize <number> Size in bytes of the buffer allocated for each read operation. Default: 131072 (128 KB).
  • Returns: <AsyncIterable> whose chunks fulfill with <Uint8Array>[]

Return the file contents as an async iterable using the node:stream/iter pull model. Reads are performed in chunkSize-byte chunks (default 128 KB). If transforms are provided, they are applied via stream/iter pull().

The file handle is locked while the iterable is being consumed and unlocked when iteration completes, an error occurs, or the consumer breaks.

This function is only available when the --experimental-stream-iter flag is enabled.

import { open } from 'node:fs/promises';
import { text } from 'node:stream/iter';
import { compressGzip } from 'node:zlib/iter';

const fh = await open('input.txt', 'r');

// Read as text
console.log(await text(fh.pull({ autoClose: true })));

// Read 1 KB starting at byte 100
const fh2 = await open('input.txt', 'r');
console.log(await text(fh2.pull({ start: 100, limit: 1024, autoClose: true })));

// Read with compression
const fh3 = await open('input.txt', 'r');
const compressed = fh3.pull(compressGzip(), { autoClose: true });
const { open } = require('node:fs/promises');
const { text } = require('node:stream/iter');
const { compressGzip } = require('node:zlib/iter');

async function run() {
  const fh = await open('input.txt', 'r');

  // Read as text
  console.log(await text(fh.pull({ autoClose: true })));

  // Read 1 KB starting at byte 100
  const fh2 = await open('input.txt', 'r');
  console.log(await text(fh2.pull({ start: 100, limit: 1024, autoClose: true })));

  // Read with compression
  const fh3 = await open('input.txt', 'r');
  const compressed = fh3.pull(compressGzip(), { autoClose: true });
}

run().catch(console.error);
javascript
filehandle.pullSync([...transforms][, options])#

Stability: 1 - Experimental

  • ...transforms <Function> | <Object> Optional transforms to apply via stream/iter pullSync().
  • options <Object>
    • autoClose <boolean> Close the file handle when the stream ends. Default: false.
    • start <number> Byte offset to begin reading from. When specified, reads use explicit positioning. Default: current file position.
    • limit <number> Maximum number of bytes to read before ending the iterator. Default: read until EOF.
    • chunkSize <number> Size in bytes of the buffer allocated for each read operation. Default: 131072 (128 KB).
  • Returns: <Iterable> whose chunks return <Uint8Array>[]

Synchronous counterpart of filehandle.pull(). Returns a sync iterable that reads the file using synchronous I/O on the main thread. Reads are performed in chunkSize-byte chunks (default 128 KB).

The file handle is locked while the iterable is being consumed. Unlike the async pull(), this method does not support AbortSignal since all operations are synchronous.

This function is only available when the --experimental-stream-iter flag is enabled.

import { open } from 'node:fs/promises';
import { textSync, pipeToSync } from 'node:stream/iter';
import { compressGzipSync, decompressGzipSync } from 'node:zlib/iter';

const fh = await open('input.txt', 'r');

// Read as text (sync)
console.log(textSync(fh.pullSync({ autoClose: true })));

// Sync compress pipeline: file -> gzip -> file
const src = await open('input.txt', 'r');
const dst = await open('output.gz', 'w');
pipeToSync(src.pullSync(compressGzipSync(), { autoClose: true }), dst.writer({ autoClose: true }));
const { open } = require('node:fs/promises');
const { textSync, pipeToSync } = require('node:stream/iter');
const { compressGzipSync, decompressGzipSync } = require('node:zlib/iter');

async function run() {
  const fh = await open('input.txt', 'r');

  // Read as text (sync)
  console.log(textSync(fh.pullSync({ autoClose: true })));

  // Sync compress pipeline: file -> gzip -> file
  const src = await open('input.txt', 'r');
  const dst = await open('output.gz', 'w');
  pipeToSync(
    src.pullSync(compressGzipSync(), { autoClose: true }),
    dst.writer({ autoClose: true }),
  );
}

run().catch(console.error);
javascript
filehandle.read(buffer, offset, length, position)#
  • buffer <Buffer> | <TypedArray> | <DataView> A buffer that will be filled with the file data read.
  • offset <integer> The location in the buffer at which to start filling. Default: 0
  • length <integer> The number of bytes to read. Default: buffer.byteLength - offset
  • position <integer> | <bigint> | <null> The location where to begin reading data from the file. If null or -1, data will be read from the current file position, and the position will be updated. If position is a non-negative integer, the current file position will remain unchanged. Default: null
  • Returns: <Promise> Fulfills upon success with an object with two properties:

Reads data from the file and stores that in the given buffer.

If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero.

filehandle.read([options])#
  • options <Object>
    • buffer <Buffer> | <TypedArray> | <DataView> A buffer that will be filled with the file data read. Default: Buffer.alloc(16384)
    • offset <integer> The location in the buffer at which to start filling. Default: 0
    • length <integer> The number of bytes to read. Default: buffer.byteLength - offset
    • position <integer> | <bigint> | <null> The location where to begin reading data from the file. If null or -1, data will be read from the current file position, and the position will be updated. If position is a non-negative integer, the current file position will remain unchanged. Default:: null
  • Returns: <Promise> Fulfills upon success with an object with two properties:

Reads data from the file and stores that in the given buffer.

If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero.

filehandle.read(buffer[, options])#
  • buffer <Buffer> | <TypedArray> | <DataView> A buffer that will be filled with the file data read.
  • options <Object>
    • offset <integer> The location in the buffer at which to start filling. Default: 0
    • length <integer> The number of bytes to read. Default: buffer.byteLength - offset
    • position <integer> | <bigint> | <null> The location where to begin reading data from the file. If null or -1, data will be read from the current file position, and the position will be updated. If position is a non-negative integer, the current file position will remain unchanged. Default:: null
  • Returns: <Promise> Fulfills upon success with an object with two properties:

Reads data from the file and stores that in the given buffer.

If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero.

filehandle.readableWebStream([options])#

Returns a byte-oriented ReadableStream that may be used to read the file's contents.

An error will be thrown if this method is called more than once or is called after the FileHandle is closed or closing.

import {
  open,
} from 'node:fs/promises';

const file = await open('./some/file/to/read');

for await (const chunk of file.readableWebStream())
  console.log(chunk);

await file.close();
const {
  open,
} = require('node:fs/promises');

(async () => {
  const file = await open('./some/file/to/read');

  for await (const chunk of file.readableWebStream())
    console.log(chunk);

  await file.close();
})();
javascript

While the ReadableStream will read the file to completion, it will not close the FileHandle automatically. User code must still call the fileHandle.close() method unless the autoClose option is set to true.

filehandle.readFile(options)#

Asynchronously reads the entire contents of a file.

If options is a string, then it specifies the encoding.

If buffer is provided and no encoding is specified, the returned <Buffer> is a view over the supplied buffer containing only the bytes read. If the supplied buffer is too small to contain the entire file, the operation will fail.

The <FileHandle> has to support reading.

If one or more filehandle.read() calls are made on a file handle and then a filehandle.readFile() call is made, the data will be read from the current position till the end of the file. It doesn't always read from the beginning of the file.

An example using the buffer option with a pre-allocated buffer:

import { Buffer } from 'node:buffer';
import { open } from 'node:fs/promises';

const file = await open('./some/file/to/read');
try {
  const buf = Buffer.alloc(16384);
  const contents = await file.readFile({ buffer: buf });
  console.log(contents); // A view over `buf` containing only the bytes read
} finally {
  await file.close();
}
mjs

An example using the buffer option with a function returning a buffer:

import { Buffer } from 'node:buffer';
import { open } from 'node:fs/promises';

const file = await open('./some/file/to/read');
try {
  const contents = await file.readFile({
    buffer: (size) => Buffer.alloc(size),
  });
  console.log(contents);
} finally {
  await file.close();
}
mjs
filehandle.readLines([options])#

Convenience method to create a readline interface and stream over the file. See filehandle.createReadStream() for the options.

import { open } from 'node:fs/promises';

const file = await open('./some/file/to/read');

for await (const line of file.readLines()) {
  console.log(line);
}
const { open } = require('node:fs/promises');

(async () => {
  const file = await open('./some/file/to/read');

  for await (const line of file.readLines()) {
    console.log(line);
  }
})();
javascript
filehandle.readv(buffers[, position])#
  • buffers <Buffer>[] | <TypedArray>[] | <DataView>[]
  • position <integer> | <null> The offset from the beginning of the file where the data should be read from. If position is not a number, the data will be read from the current position. Default: null
  • Returns: <Promise> Fulfills upon success an object containing two properties:

Read from a file and write to an array of <ArrayBufferView>s

filehandle.stat([options])#
filehandle.sync()#
  • Returns: <Promise> Fulfills with undefined upon success.

Request that all data for the open file descriptor is flushed to the storage device. The specific implementation is operating system and device specific. Refer to the POSIX fsync(2) documentation for more detail.

filehandle.truncate(len)#

Truncates the file.

If the file was larger than len bytes, only the first len bytes will be retained in the file.

The following example retains only the first four bytes of the file:

import { open } from 'node:fs/promises';

let filehandle = null;
try {
  filehandle = await open('temp.txt', 'r+');
  await filehandle.truncate(4);
} finally {
  await filehandle?.close();
}
mjs

If the file previously was shorter than len bytes, it is extended, and the extended part is filled with null bytes ('\0'):

If len is negative then 0 will be used.

filehandle.utimes(atime, mtime)#

Change the file system timestamps of the object referenced by the <FileHandle> then fulfills the promise with no arguments upon success.

filehandle.write(buffer, offset[, length[, position]])#
  • buffer <Buffer> | <TypedArray> | <DataView>
  • offset <integer> The start position from within buffer where the data to write begins.
  • length <integer> The number of bytes from buffer to write. Default: buffer.byteLength - offset
  • position <integer> | <null> The offset from the beginning of the file where the data from buffer should be written. If position is not a number, the data will be written at the current position. See the POSIX pwrite(2) documentation for more detail. Default: null
  • Returns: <Promise>

Write buffer to the file.

The promise is fulfilled with an object containing two properties:

It is unsafe to use filehandle.write() multiple times on the same file without waiting for the promise to be fulfilled (or rejected). For this scenario, use filehandle.createWriteStream().

On Linux, positional writes do not work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

filehandle.write(buffer[, options])#

Write buffer to the file.

Similar to the above filehandle.write function, this version takes an optional options object. If no options object is specified, it will default with the above values.

filehandle.write(string[, position[, encoding]])#
  • string <string>
  • position <integer> | <null> The offset from the beginning of the file where the data from string should be written. If position is not a number the data will be written at the current position. See the POSIX pwrite(2) documentation for more detail. Default: null
  • encoding <string> The expected string encoding. Default: 'utf8'
  • Returns: <Promise>

Write string to the file. If string is not a string, the promise is rejected with an error.

The promise is fulfilled with an object containing two properties:

  • bytesWritten <integer> the number of bytes written
  • buffer <string> a reference to the string written.

It is unsafe to use filehandle.write() multiple times on the same file without waiting for the promise to be fulfilled (or rejected). For this scenario, use filehandle.createWriteStream().

On Linux, positional writes do not work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

filehandle.writeFile(data, options)#

Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an <AsyncIterable>, or an <Iterable> object. The promise is fulfilled with no arguments upon success.

If options is a string, then it specifies the encoding.

The <FileHandle> has to support writing.

It is unsafe to use filehandle.writeFile() multiple times on the same file without waiting for the promise to be fulfilled (or rejected).

If one or more filehandle.write() calls are made on a file handle and then a filehandle.writeFile() call is made, the data will be written from the current position till the end of the file. It doesn't always write from the beginning of the file.

filehandle.writev(buffers[, position])#
  • buffers <Buffer>[] | <TypedArray>[] | <DataView>[]
  • position <integer> | <null> The offset from the beginning of the file where the data from buffers should be written. If position is not a number, the data will be written at the current position. Default: null
  • Returns: <Promise>

Write an array of <ArrayBufferView>s to the file.

The promise is fulfilled with an object containing a two properties:

It is unsafe to call writev() multiple times on the same file without waiting for the promise to be fulfilled (or rejected).

On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

filehandle.writer([options])#

Stability: 1 - Experimental

  • options <Object>
    • autoClose <boolean> Close the file handle when the writer ends or fails. Default: false.
    • start <number> Byte offset to start writing at. When specified, writes use explicit positioning. Default: current file position.
    • limit <number> Maximum number of bytes the writer will accept. Async writes (write(), writev()) that would exceed the limit reject with ERR_OUT_OF_RANGE. Sync writes (writeSync(), writevSync()) return false. Default: no limit.
    • chunkSize <number> Maximum chunk size in bytes for synchronous write operations. Writes larger than this threshold fall back to async I/O. Set this to match the reader's chunkSize for optimal pipeTo() performance. Default: 131072 (128 KB).
  • Returns: <Object>
    • write(chunk[, options]) <Function> Returns <Promise>. Accepts Uint8Array, Buffer, or string (UTF-8 encoded).
    • writev(chunks[, options]) <Function> Returns <Promise>. Uses scatter/gather I/O via a single writev() syscall. Accepts mixed Uint8Array/string arrays.
    • writeSync(chunk) <Function> Returns <boolean>. Attempts a synchronous write. Returns true if the write succeeded, false if the caller should fall back to async write(). Returns false when: the writer is closed/errored, an async operation is in flight, the chunk exceeds chunkSize, or the write would exceed limit.
    • writevSync(chunks) <Function> Returns <boolean>. Synchronous batch write. Same fallback semantics as writeSync().
    • end([options]) <Function> Returns <Promise>, fulfills with the total number of bytes written. Idempotent: returns totalBytesWritten if already closed, returns the pending promise if already closing. Rejects if the writer is in an errored state.
      • options <Object>
        • signal <AbortSignal> If the signal is already aborted, end() rejects with AbortError and the writer remains open.
    • endSync() <Function> Returns <number> | <number> total bytes written on success, -1 if the writer is errored or an async operation is in flight. Idempotent when already closed.
    • fail(reason) <Function> Puts the writer into a terminal error state. Synchronous. If the writer is already closed or errored, this is a no-op. If autoClose is true, closes the file handle synchronously.

Return a node:stream/iter writer backed by this file handle.

The writer supports both Symbol.asyncDispose and Symbol.dispose:

  • await using w = fh.writer() — if the writer is still open (no end() called), asyncDispose calls fail(). If end() is pending, it waits for it to complete.
  • using w = fh.writer() — calls fail() unconditionally.

The writeSync() and writevSync() methods enable the try-sync fast path used by stream/iter pipeTo(). When the reader's chunk size matches the writer's chunkSize, all writes in a pipeTo() pipeline complete synchronously with zero promise overhead.

This function is only available when the --experimental-stream-iter flag is enabled.

import { open } from 'node:fs/promises';
import { from, pipeTo } from 'node:stream/iter';
import { compressGzip } from 'node:zlib/iter';

// Async pipeline
const fh = await open('output.gz', 'w');
await pipeTo(from('Hello!'), compressGzip(), fh.writer({ autoClose: true }));

// Sync pipeline with limit
const src = await open('input.txt', 'r');
const dst = await open('output.txt', 'w');
const w = dst.writer({ limit: 1024 * 1024 }); // Max 1 MB
await pipeTo(src.pull({ autoClose: true }), w);
await w.end();
await dst.close();
const { open } = require('node:fs/promises');
const { from, pipeTo } = require('node:stream/iter');
const { compressGzip } = require('node:zlib/iter');

async function run() {
  // Async pipeline
  const fh = await open('output.gz', 'w');
  await pipeTo(from('Hello!'), compressGzip(), fh.writer({ autoClose: true }));

  // Sync pipeline with limit
  const src = await open('input.txt', 'r');
  const dst = await open('output.txt', 'w');
  const w = dst.writer({ limit: 1024 * 1024 }); // Max 1 MB
  await pipeTo(src.pull({ autoClose: true }), w);
  await w.end();
  await dst.close();
}

run().catch(console.error);
javascript
filehandle[Symbol.asyncDispose]()#

Calls filehandle.close() and returns a promise that fulfills when the filehandle is closed.

This method enables the filehandle to be used with await using, which will automatically close the file when the scope exits. For more information, see the MDN documentation on using statements.

fsPromises.access(path[, mode])#

Tests a user's permissions for the file or directory specified by path. The mode argument is an optional integer that specifies the accessibility checks to be performed. mode should be either the value fs.constants.F_OK or a mask consisting of the bitwise OR of any of fs.constants.R_OK, fs.constants.W_OK, and fs.constants.X_OK (e.g. fs.constants.W_OK | fs.constants.R_OK). Check File access constants for possible values of mode.

If the accessibility check is successful, the promise is fulfilled with no value. If any of the accessibility checks fail, the promise is rejected with an <Error> object. The following example checks if the file /etc/passwd can be read and written by the current process.

import { access, constants } from 'node:fs/promises';

try {
  await access('/etc/passwd', constants.R_OK | constants.W_OK);
  console.log('can access');
} catch {
  console.error('cannot access');
}
mjs

Using fsPromises.access() to check for the accessibility of a file before calling fsPromises.open() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible.

fsPromises.appendFile(path, data[, options])#

Asynchronously append data to a file, creating the file if it does not yet data can be a string, a buffer, an <AsyncIterable>, or an <Iterable> object.

If options is a string, then it specifies the encoding.

The mode option only affects the newly created file. See fs.open() for more details.

The path may be specified as a <FileHandle> that has been opened for appending (using fsPromises.open()).

fsPromises.chmod(path, mode)#

Changes the permissions of a file.

fsPromises.chown(path, uid, gid)#

Changes the ownership of a file.

fsPromises.copyFile(src, dest[, mode])#

  • src <string> | <Buffer> | <URL> source filename to copy
  • dest <string> | <Buffer> | <URL> destination filename of the copy operation
  • mode <integer> Optional modifiers that specify the behavior of the copy operation. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE) Default: 0.
    • fs.constants.COPYFILE_EXCL: The copy operation will fail if dest already exists.
    • fs.constants.COPYFILE_FICLONE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then a fallback copy mechanism is used.
    • fs.constants.COPYFILE_FICLONE_FORCE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then the operation will fail.
  • Returns: <Promise> Fulfills with undefined upon success.

Asynchronously copies src to dest. By default, dest is overwritten if it already exists.

No guarantees are made about the atomicity of the copy operation. If an error occurs after the destination file has been opened for writing, an attempt will be made to remove the destination.

import { copyFile, constants } from 'node:fs/promises';

try {
  await copyFile('source.txt', 'destination.txt');
  console.log('source.txt was copied to destination.txt');
} catch {
  console.error('The file could not be copied');
}

// By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
try {
  await copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL);
  console.log('source.txt was copied to destination.txt');
} catch {
  console.error('The file could not be copied');
}
mjs

fsPromises.cp(src, dest[, options])#

  • src <string> | <URL> source path to copy.
  • dest <string> | <URL> destination path to copy to.
  • options <Object>
    • dereference <boolean> dereference symlinks. Default: false.
    • errorOnExist <boolean> when force is false, and the destination exists, throw an error. Default: false.
    • filter <Function> Function to filter copied files/directories. Return true to copy the item, false to ignore it. When ignoring a directory, all of its contents will be skipped as well. Can also return a Promise that resolves to true or false Default: undefined.
      • src <string> source path to copy.
      • dest <string> destination path to copy to.
      • Returns: <boolean> | <Promise> A value that is coercible to boolean or a Promise that fulfils with such value.
    • force <boolean> overwrite existing file or directory. The copy operation will ignore errors if you set this to false and the destination exists. Use the errorOnExist option to change this behavior. Default: true.
    • mode <integer> modifiers for copy operation. Default: 0. See mode flag of fsPromises.copyFile().
    • preserveTimestamps <boolean> When true timestamps from src will be preserved. Default: false.
    • recursive <boolean> copy directories recursively Default: false
    • verbatimSymlinks <boolean> When true, path resolution for symlinks will be skipped. Default: false
  • Returns: <Promise> Fulfills with undefined upon success.

Asynchronously copies the entire directory structure from src to dest, including subdirectories and files.

When copying a directory to another directory, globs are not supported and behavior is similar to cp dir1/ dir2/.

fsPromises.glob(pattern[, options])#

  • pattern <string> | <string>[]
  • options <Object>
    • cwd <string> | <URL> current working directory. Default: process.cwd()
    • exclude <Function> | <string>[] Function to filter out files/directories or a list of glob patterns to be excluded. If a function is provided, return true to exclude the item, false to include it. Default: undefined. If a string array is provided, each string should be a glob pattern that specifies paths to exclude. Note: Negation patterns (e.g., '!foo.js') are not supported.
    • followSymlinks <boolean> When true, symbolic links to directories are followed while expanding ** patterns. Default: false.
    • withFileTypes <boolean> true if the glob should return paths as Dirents, false otherwise. Default: false.
  • Returns: <AsyncIterator> An AsyncIterator that yields the paths of files that match the pattern.

When followSymlinks is enabled, detected symbolic link cycles are not traversed recursively.

import { glob } from 'node:fs/promises';

for await (const entry of glob('**/*.js'))
  console.log(entry);
const { glob } = require('node:fs/promises');

(async () => {
  for await (const entry of glob('**/*.js'))
    console.log(entry);
})();
javascript

fsPromises.lchmod(path, mode)#

Stability: 0 - Deprecated

Changes the permissions on a symbolic link.

This method is only implemented on macOS.

fsPromises.lchown(path, uid, gid)#

Changes the ownership on a symbolic link.

fsPromises.lutimes(path, atime, mtime)#

Changes the access and modification times of a file in the same way as fsPromises.utimes(), with the difference that if the path refers to a symbolic link, then the link is not dereferenced: instead, the timestamps of the symbolic link itself are changed.

fsPromises.link(existingPath, newPath)#

Creates a new link from the existingPath to the newPath. See the POSIX link(2) documentation for more detail.

fsPromises.lstat(path[, options])#

Equivalent to fsPromises.stat() unless path refers to a symbolic link, in which case the link itself is stat-ed, not the file that it refers to. Refer to the POSIX lstat(2) document for more detail.

fsPromises.mkdir(path[, options])#

Asynchronously creates a directory.

The optional options argument can be an integer specifying mode (permission and sticky bits), or an object with a mode property and a recursive property indicating whether parent directories should be created. Calling fsPromises.mkdir() when path is a directory that exists results in a rejection only when recursive is false.

import { mkdir } from 'node:fs/promises';

try {
  const projectFolder = new URL('./test/project/', import.meta.url);
  const createDir = await mkdir(projectFolder, { recursive: true });

  console.log(`created ${createDir}`);
} catch (err) {
  console.error(err.message);
}
const { mkdir } = require('node:fs/promises');
const { join } = require('node:path');

async function makeDirectory() {
  const projectFolder = join(__dirname, 'test', 'project');
  const dirCreation = await mkdir(projectFolder, { recursive: true });

  console.log(dirCreation);
  return dirCreation;
}

makeDirectory().catch(console.error);
javascript

fsPromises.mkdtemp(prefix[, options])#

Creates a unique temporary directory. A unique directory name is generated by appending six random characters to the end of the provided prefix. Due to platform inconsistencies, avoid trailing X characters in prefix. Some platforms, notably the BSDs, can return more than six random characters, and replace trailing X characters in prefix with random characters.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use.

import { mkdtemp } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

try {
  await mkdtemp(join(tmpdir(), 'foo-'));
} catch (err) {
  console.error(err);
}
mjs

The fsPromises.mkdtemp() method will append the six randomly selected characters directly to the prefix string. For instance, given a directory /tmp, if the intention is to create a temporary directory within /tmp, the prefix must end with a trailing platform-specific path separator (require('node:path').sep).

fsPromises.mkdtempDisposable(prefix[, options])#

The resulting Promise holds an async-disposable object whose path property holds the created directory path. When the object is disposed, the directory and its contents will be removed asynchronously if it still exists. If the directory cannot be deleted, disposal will throw an error. The object has an async remove() method which will perform the same task.

Both this function and the disposal function on the resulting object are async, so it should be used with await + await using as in await using dir = await fsPromises.mkdtempDisposable('prefix').

See the MDN documentation on using statements for more information about explicit resource management.

For detailed information, see the documentation of fsPromises.mkdtemp().

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use.

fsPromises.open(path, flags[, mode])#

Opens a <FileHandle>.

Refer to the POSIX open(2) documentation for more detail.

Some characters (< > : " / \ | ? *) are reserved under Windows as documented by Naming Files, Paths, and Namespaces. Under NTFS, if the filename contains a colon, Node.js will open a file system stream, as described by this MSDN page.

fsPromises.opendir(path[, options])#

Asynchronously open a directory for iterative scanning. See the POSIX opendir(3) documentation for more detail.

Creates an <fs.Dir>, which contains all further functions for reading from and cleaning up the directory.

The encoding option sets the encoding for the path while opening the directory and subsequent read operations.

Example using async iteration:

import { opendir } from 'node:fs/promises';

try {
  const dir = await opendir('./');
  for await (const dirent of dir)
    console.log(dirent.name);
} catch (err) {
  console.error(err);
}
mjs

When using the async iterator, the <fs.Dir> object will be automatically closed after the iterator exits.

fsPromises.readdir(path[, options])#

  • path <string> | <Buffer> | <URL>
  • options <string> | <Object>
    • encoding <string> Default: 'utf8'
    • withFileTypes <boolean> Default: false
    • recursive <boolean> If true, reads the contents of a directory recursively. In recursive mode, it will list all files, sub files, and directories. Default: false.
  • Returns: <Promise> Fulfills with an array of the names of the files in the directory excluding '.' and '..'.

Reads the contents of a directory.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the filenames. If the encoding is set to 'buffer', the filenames returned will be passed as <Buffer> objects.

If options.withFileTypes is set to true, the returned array will contain <fs.Dirent> objects.

import { readdir } from 'node:fs/promises';

try {
  const files = await readdir(path);
  for (const file of files)
    console.log(file);
} catch (err) {
  console.error(err);
}
mjs

fsPromises.readFile(path[, options])#

Asynchronously reads the entire contents of a file.

If no encoding is specified (using options.encoding), the data is returned as a <Buffer> object. Otherwise, the data will be a string.

If options is a string, then it specifies the encoding.

If buffer is provided and no encoding is specified, the returned <Buffer> is a view over the supplied buffer containing only the bytes read. If the supplied buffer is too small to contain the entire file, the promise will be rejected.

When the path is a directory, the behavior of fsPromises.readFile() is platform-specific. On macOS, Linux, and Windows, the promise will be rejected with an error. On FreeBSD, a representation of the directory's contents will be returned.

An example of reading a package.json file located in the same directory of the running code:

import { readFile } from 'node:fs/promises';
try {
  const filePath = new URL('./package.json', import.meta.url);
  const contents = await readFile(filePath, { encoding: 'utf8' });
  console.log(contents);
} catch (err) {
  console.error(err.message);
}
const { readFile } = require('node:fs/promises');
const { resolve } = require('node:path');
async function logFile() {
  try {
    const filePath = resolve('./package.json');
    const contents = await readFile(filePath, { encoding: 'utf8' });
    console.log(contents);
  } catch (err) {
    console.error(err.message);
  }
}
logFile();
javascript

It is possible to abort an ongoing readFile using an <AbortSignal>. If a request is aborted the promise returned is rejected with an AbortError:

import { readFile } from 'node:fs/promises';

try {
  const controller = new AbortController();
  const { signal } = controller;
  const promise = readFile(fileName, { signal });

  // Abort the request before the promise settles.
  controller.abort();

  await promise;
} catch (err) {
  // When a request is aborted - err is an AbortError
  console.error(err);
}
mjs

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.readFile performs.

Any specified <FileHandle> has to support reading.

An example using the buffer option with a pre-allocated buffer:

import { Buffer } from 'node:buffer';
import { readFile } from 'node:fs/promises';

const buf = Buffer.alloc(16384);
const contents = await readFile('/path/to/file', { buffer: buf });
console.log(contents); // A view over `buf` containing only the bytes read
mjs

An example using the buffer option with a function returning a buffer:

import { Buffer } from 'node:buffer';
import { readFile } from 'node:fs/promises';

const contents = await readFile('/path/to/file', {
  buffer: (size) => Buffer.alloc(size),
});
console.log(contents);
mjs

fsPromises.readlink(path[, options])#

Reads the contents of the symbolic link referred to by path. See the POSIX readlink(2) documentation for more detail. The promise is fulfilled with the linkString upon success.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the link path returned. If the encoding is set to 'buffer', the link path returned will be passed as a <Buffer> object.

fsPromises.realpath(path[, options])#

Determines the actual location of path using the same semantics as the fs.realpath.native() function.

Only paths that can be converted to UTF8 strings are supported.

The optional options argument can be a string specifying an encoding, or an object with an encoding property specifying the character encoding to use for the path. If the encoding is set to 'buffer', the path returned will be passed as a <Buffer> object.

On Linux, when Node.js is linked against musl libc, the procfs file system must be mounted on /proc in order for this function to work. Glibc does not have this restriction.

fsPromises.rename(oldPath, newPath)#

Renames oldPath to newPath.

fsPromises.rmdir(path[, options])#

  • path <string> | <Buffer> | <URL>
  • options <Object> There are currently no options exposed. There used to be options for recursive, maxBusyTries, and emfileWait but they were deprecated and removed. The options argument is still accepted for backwards compatibility but it is not used.
  • Returns: <Promise> Fulfills with undefined upon success.

Removes the directory identified by path.

Using fsPromises.rmdir() on a file (not a directory) results in the promise being rejected with an ENOENT error on Windows and an ENOTDIR error on POSIX.

To get a behavior similar to the rm -rf Unix command, use fsPromises.rm() with options { recursive: true, force: true }.

fsPromises.rm(path[, options])#

  • path <string> | <Buffer> | <URL>
  • options <Object>
    • force <boolean> When true, exceptions will be ignored if path does not exist. Default: false.
    • maxRetries <integer> If an EBUSY, EMFILE, ENFILE, ENOTEMPTY, or EPERM error is encountered, Node.js will retry the operation with a linear backoff wait of retryDelay milliseconds longer on each try. This option represents the number of retries. This option is ignored if the recursive option is not true. Default: 0.
    • recursive <boolean> If true, perform a recursive directory removal. In recursive mode operations are retried on failure. Default: false.
    • retryDelay <integer> The amount of time in milliseconds to wait between retries. This option is ignored if the recursive option is not true. Default: 100.
  • Returns: <Promise> Fulfills with undefined upon success.

Removes files and directories (modeled on the standard POSIX rm utility).

fsPromises.stat(path[, options])#

  • path <string> | <Buffer> | <URL>
  • options <Object>
    • bigint <boolean> Whether the numeric values in the returned <fs.Stats> object should be bigint. Default: false.
    • throwIfNoEntry <boolean> Whether an exception will be thrown if no file system entry exists, rather than returning undefined. Default: true.
  • Returns: <Promise> Fulfills with the <fs.Stats> object for the given path.

fsPromises.statfs(path[, options])#

fsPromises.symlink(target, path[, type])#

Creates a symbolic link.

The type argument is only used on Windows platforms and can be one of 'dir', 'file', or 'junction'. If the type argument is null, Node.js will autodetect target type and use 'file' or 'dir'. If the target does not exist, 'file' will be used. Windows junction points require the destination path to be absolute. When using 'junction', the target argument will automatically be normalized to absolute path. Junction points on NTFS volumes can only point to directories.

fsPromises.truncate(path[, len])#

Truncates (shortens or extends the length) of the content at path to len bytes.

fsPromises.unlink(path)#

If path refers to a symbolic link, then the link is removed without affecting the file or directory to which that link refers. If the path refers to a file path that is not a symbolic link, the file is deleted. See the POSIX unlink(2) documentation for more detail.

fsPromises.utimes(path, atime, mtime)#

Change the file system timestamps of the object referenced by path.

The atime and mtime arguments follow these rules:

  • Values can be either numbers representing Unix epoch time, Dates, or a numeric string like '123456789.0'.
  • If the value can not be converted to a number, or is NaN, Infinity, or -Infinity, an Error will be thrown.

fsPromises.watch(filename[, options])#

  • filename <string> | <Buffer> | <URL>
  • options <string> | <Object>
    • persistent <boolean> Indicates whether the process should continue to run as long as files are being watched. Default: true.
    • recursive <boolean> Indicates whether all subdirectories should be watched, or only the current directory. This applies when a directory is specified, and only on supported platforms (See caveats). Default: false.
    • encoding <string> Specifies the character encoding to be used for the filename passed to the listener. Default: 'utf8'.
    • signal <AbortSignal> An <AbortSignal> used to signal when the watcher should stop.
    • maxQueue <number> Specifies the number of events to queue between iterations of the <AsyncIterator> returned. Default: 2048.
    • overflow <string> Either 'ignore' or 'throw' when there are more events to be queued than maxQueue allows. 'ignore' means overflow events are dropped and a warning is emitted, while 'throw' means to throw an exception. Default: 'ignore'.
    • ignore <string> | <RegExp> | <Function> | <Array> Pattern(s) to ignore. Strings are glob patterns (using minimatch), RegExp patterns are tested against the filename, and functions receive the filename and return true to ignore. Default: undefined.
  • Returns: <AsyncIterator> of objects with the properties:

Returns an async iterator that watches for changes on filename, where filename is either a file or a directory.

const { watch } = require('node:fs/promises');

const ac = new AbortController();
const { signal } = ac;
setTimeout(() => ac.abort(), 10000);

(async () => {
  try {
    const watcher = watch(__filename, { signal });
    for await (const event of watcher)
      console.log(event);
  } catch (err) {
    if (err.name === 'AbortError')
      return;
    throw err;
  }
})();
js

On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.

All the caveats for fs.watch() also apply to fsPromises.watch().

fsPromises.writeFile(file, data[, options])#

Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an <AsyncIterable>, or an <Iterable> object.

The encoding option is ignored if data is a buffer.

If options is a string, then it specifies the encoding.

The mode option only affects the newly created file. See fs.open() for more details.

Any specified <FileHandle> has to support writing.

It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.

Similarly to fsPromises.readFile - fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream().

It is possible to use an <AbortSignal> to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.

import { writeFile } from 'node:fs/promises';
import { Buffer } from 'node:buffer';

try {
  const controller = new AbortController();
  const { signal } = controller;
  const data = new Uint8Array(Buffer.from('Hello Node.js'));
  const promise = writeFile('message.txt', data, { signal });

  // Abort the request before the promise settles.
  controller.abort();

  await promise;
} catch (err) {
  // When a request is aborted - err is an AbortError
  console.error(err);
}
mjs

Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.

fsPromises.constants#

Returns an object containing commonly used constants for file system operations. The object is the same as fs.constants. See FS constants for more details.

Callback API#

The callback APIs perform all operations asynchronously, without blocking the event loop, then invoke a callback function upon completion or error.

The callback APIs use the underlying Node.js threadpool to perform file system operations off the event loop thread. These operations are not synchronized or threadsafe. Care must be taken when performing multiple concurrent modifications on the same file or data corruption may occur.

fs.access(path[, mode], callback)#

Tests a user's permissions for the file or directory specified by path. The mode argument is an optional integer that specifies the accessibility checks to be performed. mode should be either the value fs.constants.F_OK or a mask consisting of the bitwise OR of any of fs.constants.R_OK, fs.constants.W_OK, and fs.constants.X_OK (e.g. fs.constants.W_OK | fs.constants.R_OK). Check File access constants for possible values of mode.

The final argument, callback, is a callback function that is invoked with a possible error argument. If any of the accessibility checks fail, the error argument will be an Error object. The following examples check if package.json exists, and if it is readable or writable.

import { access, constants } from 'node:fs';

const file = 'package.json';

// Check if the file exists in the current directory.
access(file, constants.F_OK, (err) => {
  console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});

// Check if the file is readable.
access(file, constants.R_OK, (err) => {
  console.log(`${file} ${err ? 'is not readable' : 'is readable'}`);
});

// Check if the file is writable.
access(file, constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not writable' : 'is writable'}`);
});

// Check if the file is readable and writable.
access(file, constants.R_OK | constants.W_OK, (err) => {
  console.log(`${file} ${err ? 'is not' : 'is'} readable and writable`);
});
mjs

Do not use fs.access() to check for the accessibility of a file before calling fs.open(), fs.readFile(), or fs.writeFile(). Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible.

write (NOT RECOMMENDED)

import { access, open, close } from 'node:fs';

access('myfile', (err) => {
  if (!err) {
    console.error('myfile already exists');
    return;
  }

  open('myfile', 'wx', (err, fd) => {
    if (err) throw err;

    try {
      writeMyData(fd);
    } finally {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
  });
});
mjs

write (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile already exists');
      return;
    }

    throw err;
  }

  try {
    writeMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});
mjs

read (NOT RECOMMENDED)

import { access, open, close } from 'node:fs';
access('myfile', (err) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  open('myfile', 'r', (err, fd) => {
    if (err) throw err;

    try {
      readMyData(fd);
    } finally {
      close(fd, (err) => {
        if (err) throw err;
      });
    }
  });
});
mjs

read (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  try {
    readMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});
mjs

The "not recommended" examples above check for accessibility and then use the file; the "recommended" examples are better because they use the file directly and handle the error, if any.

In general, check for the accessibility of a file only if the file will not be used directly, for example when its accessibility is a signal from another process.

On Windows, access-control policies (ACLs) on a directory may limit access to a file or directory. The fs.access() function, however, does not check the ACL and therefore may report that a path is accessible even if the ACL restricts the user from reading or writing to it.

fs.appendFile(path, data[, options], callback)#

Asynchronously append data to a file, creating the file if it does not yet exist. data can be a string or a <Buffer>.

The mode option only affects the newly created file. See fs.open() for more details.

import { appendFile } from 'node:fs';

appendFile('message.txt', 'data to append', (err) => {
  if (err) throw err;
  console.log('The "data to append" was appended to file!');
});
mjs

If options is a string, then it specifies the encoding:

import { appendFile } from 'node:fs';

appendFile('message.txt', 'data to append', 'utf8', callback);
mjs

The path may be specified as a numeric file descriptor that has been opened for appending (using fs.open() or fs.openSync()). The file descriptor will not be closed automatically.

import { open, close, appendFile } from 'node:fs';

function closeFd(fd) {
  close(fd, (err) => {
    if (err) throw err;
  });
}

open('message.txt', 'a', (err, fd) => {
  if (err) throw err;

  try {
    appendFile(fd, 'data to append', 'utf8', (err) => {
      closeFd(fd);
      if (err) throw err;
    });
  } catch (err) {
    closeFd(fd);
    throw err;
  }
});
mjs

fs.chmod(path, mode, callback)#

Asynchronously changes the permissions of a file. No arguments other than a possible exception are given to the completion callback.

See the POSIX chmod(2) documentation for more detail.

import { chmod } from 'node:fs';

chmod('my_file.txt', 0o775, (err) => {
  if (err) throw err;
  console.log('The permissions for file "my_file.txt" have been changed!');
});
mjs
File modes#

The mode argument used in both the fs.chmod() and fs.chmodSync() methods is a numeric bitmask created using a logical OR of the following constants:

Constant Octal Description
fs.constants.S_IRUSR 0o400 read by owner
fs.constants.S_IWUSR 0o200 write by owner
fs.constants.S_IXUSR 0o100 execute/search by owner
fs.constants.S_IRGRP 0o40 read by group
fs.constants.S_IWGRP 0o20 write by group
fs.constants.S_IXGRP 0o10 execute/search by group
fs.constants.S_IROTH 0o4 read by others
fs.constants.S_IWOTH 0o2 write by others
fs.constants.S_IXOTH 0o1 execute/search by others

An easier method of constructing the mode is to use a sequence of three octal digits (e.g. 765). The left-most digit (7 in the example), specifies the permissions for the file owner. The middle digit (6 in the example), specifies permissions for the group. The right-most digit (5 in the example), specifies the permissions for others.

Number Description
7 read, write, and execute
6 read and write
5 read and execute
4 read only
3 write and execute
2 write only
1 execute only
0 no permission

For example, the octal value 0o765 means:

  • The owner may read, write, and execute the file.
  • The group may read and write the file.
  • Others may read and execute the file.

When using raw numbers where file modes are expected, any value larger than 0o777 may result in platform-specific behaviors that are not supported to work consistently. Therefore constants like S_ISVTX, S_ISGID, or S_ISUID are not exposed in fs.constants.

Caveats: on Windows only the write permission can be changed, and the distinction among the permissions of group, owner, or others is not implemented.

fs.chown(path, uid, gid, callback)#

Asynchronously changes owner and group of a file. No arguments other than a possible exception are given to the completion callback.

See the POSIX chown(2) documentation for more detail.

fs.close(fd[, callback])#

Closes the file descriptor. No arguments other than a possible exception are given to the completion callback.

Calling fs.close() on any file descriptor (fd) that is currently in use through any other fs operation may lead to undefined behavior.

See the POSIX close(2) documentation for more detail.

fs.copyFile(src, dest[, mode], callback)#

Asynchronously copies src to dest. By default, dest is overwritten if it already exists. No arguments other than a possible exception are given to the callback function. Node.js makes no guarantees about the atomicity of the copy operation. If an error occurs after the destination file has been opened for writing, Node.js will attempt to remove the destination.

mode is an optional integer that specifies the behavior of the copy operation. It is possible to create a mask consisting of the bitwise OR of two or more values (e.g. fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE).

  • fs.constants.COPYFILE_EXCL: The copy operation will fail if dest already exists.
  • fs.constants.COPYFILE_FICLONE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then a fallback copy mechanism is used.
  • fs.constants.COPYFILE_FICLONE_FORCE: The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then the operation will fail.
import { copyFile, constants } from 'node:fs';

function callback(err) {
  if (err) throw err;
  console.log('source.txt was copied to destination.txt');
}

// destination.txt will be created or overwritten by default.
copyFile('source.txt', 'destination.txt', callback);

// By using COPYFILE_EXCL, the operation will fail if destination.txt exists.
copyFile('source.txt', 'destination.txt', constants.COPYFILE_EXCL, callback);
mjs

fs.cp(src, dest[, options], callback)#

  • src <string> | <URL> source path to copy.
  • dest <string> | <URL> destination path to copy to.
  • options <Object>
    • dereference <boolean> dereference symlinks. Default: false.
    • errorOnExist <boolean> when force is false, and the destination exists, throw an error. Default: false.
    • filter <Function> Function to filter copied files/directories. Return true to copy the item, false to ignore it. When ignoring a directory, all of its contents will be skipped as well. Can also return a Promise that fulfills with true or false. Default: undefined.
      • src <string> source path to copy.
      • dest <string> destination path to copy to.
      • Returns: <boolean> | <Promise> A value that is coercible to boolean or a Promise that fulfils with such value.
    • force <boolean> overwrite existing file or directory. The copy operation will ignore errors if you set this to false and the destination exists. Use the errorOnExist option to change this behavior. Default: true.
    • mode <integer> modifiers for copy operation. Default: 0. See mode flag of fs.copyFile().
    • preserveTimestamps <boolean> When true timestamps from src will be preserved. Default: false.
    • recursive <boolean> copy directories recursively Default: false
    • verbatimSymlinks <boolean> When true, path resolution for symlinks will be skipped. Default: false
  • callback <Function>

Asynchronously copies the entire directory structure from src to dest, including subdirectories and files.

When copying a directory to another directory, globs are not supported and behavior is similar to cp dir1/ dir2/.

fs.createReadStream(path[, options])#

options can include start and end values to read a range of bytes from the file instead of the entire file. Both start and end are inclusive and start counting at 0, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. If fd is specified and start is omitted or undefined, fs.createReadStream() reads sequentially from the current file position. The encoding can be any one of those accepted by <Buffer>.

If fd is specified, ReadStream will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be emitted. fd should be blocking; non-blocking fds should be passed to <net.Socket>.

If fd points to a character device that only supports blocking reads (such as keyboard or sound card), read operations do not finish until data is available. This can prevent the process from exiting and the stream from closing naturally.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

By providing the fs option, it is possible to override the corresponding fs implementations for open, read, and close. When providing the fs option, an override for read is required. If no fd is provided, an override for open is also required. If autoClose is true, an override for close is also required.

import { createReadStream } from 'node:fs';

// Create a stream from some character device.
const stream = createReadStream('/dev/input/event0');
setTimeout(() => {
  stream.close(); // This may not close the stream.
  // Artificially marking end-of-stream, as if the underlying resource had
  // indicated end-of-file by itself, allows the stream to close.
  // This does not cancel pending read operations, and if there is such an
  // operation, the process may still not be able to exit successfully
  // until it finishes.
  stream.push(null);
  stream.read(0);
}, 100);
mjs

If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak. If autoClose is set to true (default behavior), on 'error' or 'end' the file descriptor will be closed automatically.

mode sets the file mode (permission and sticky bits), but only if the file was created.

An example to read the last 10 bytes of a file which is 100 bytes long:

import { createReadStream } from 'node:fs';

createReadStream('sample.txt', { start: 90, end: 99 });
mjs

If options is a string, then it specifies the encoding.

fs.createWriteStream(path[, options])#

options may also include a start option to allow writing data at some position past the beginning of the file, allowed values are in the [0, Number.MAX_SAFE_INTEGER] range. Modifying a file rather than replacing it may require the flags option to be set to r+ rather than the default w. The encoding can be any one of those accepted by <Buffer>.

If autoClose is set to true (default behavior) on 'error' or 'finish' the file descriptor will be closed automatically. If autoClose is false, then the file descriptor won't be closed, even if there's an error. It is the application's responsibility to close it and make sure there's no file descriptor leak.

By default, the stream will emit a 'close' event after it has been destroyed. Set the emitClose option to false to change this behavior.

By providing the fs option it is possible to override the corresponding fs implementations for open, write, writev, and close. Overriding write() without writev() can reduce performance as some optimizations (_writev()) will be disabled. When providing the fs option, overrides for at least one of write and writev are required. If no fd option is supplied, an override for open is also required. If autoClose is true, an override for close is also required.

Like <fs.ReadStream>, if fd is specified, <fs.WriteStream> will ignore the path argument and will use the specified file descriptor. This means that no 'open' event will be emitted. fd should be blocking; non-blocking fds should be passed to <net.Socket>.

If options is a string, then it specifies the encoding.

fs.exists(path, callback)#

Stability: 0 - Deprecated: Use fs.stat() or fs.access() instead.

Test whether or not the element at the given path exists by checking with the file system. Then call the callback argument with either true or false:

import { exists } from 'node:fs';

exists('/etc/passwd', (e) => {
  console.log(e ? 'it exists' : 'no passwd!');
});
mjs

The parameters for this callback are not consistent with other Node.js callbacks. Normally, the first parameter to a Node.js callback is an err parameter, optionally followed by other parameters. The fs.exists() callback has only one boolean parameter. This is one reason fs.access() is recommended instead of fs.exists().

If path is a symbolic link, it is followed. Thus, if path exists but points to a non-existent element, the callback will receive the value false.

Using fs.exists() to check for the existence of a file before calling fs.open(), fs.readFile(), or fs.writeFile() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file does not exist.

write (NOT RECOMMENDED)

import { exists, open, close } from 'node:fs';

exists('myfile', (e) => {
  if (e) {
    console.error('myfile already exists');
  } else {
    open('myfile', 'wx', (err, fd) => {
      if (err) throw err;

      try {
        writeMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
  }
});
mjs

write (RECOMMENDED)

import { open, close } from 'node:fs';
open('myfile', 'wx', (err, fd) => {
  if (err) {
    if (err.code === 'EEXIST') {
      console.error('myfile already exists');
      return;
    }

    throw err;
  }

  try {
    writeMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});
mjs

read (NOT RECOMMENDED)

import { open, close, exists } from 'node:fs';

exists('myfile', (e) => {
  if (e) {
    open('myfile', 'r', (err, fd) => {
      if (err) throw err;

      try {
        readMyData(fd);
      } finally {
        close(fd, (err) => {
          if (err) throw err;
        });
      }
    });
  } else {
    console.error('myfile does not exist');
  }
});
mjs

read (RECOMMENDED)

import { open, close } from 'node:fs';

open('myfile', 'r', (err, fd) => {
  if (err) {
    if (err.code === 'ENOENT') {
      console.error('myfile does not exist');
      return;
    }

    throw err;
  }

  try {
    readMyData(fd);
  } finally {
    close(fd, (err) => {
      if (err) throw err;
    });
  }
});
mjs

The "not recommended" examples above check for existence and then use the file; the "recommended" examples are better because they use the file directly and handle the error, if any.

In general, check for the existence of a file only if the file won't be used directly, for example when its existence is a signal from another process.

fs.fchmod(fd, mode, callback)#

Sets the permissions on the file. No arguments other than a possible exception are given to the completion callback.

See the POSIX fchmod(2) documentation for more detail.

fs.fchown(fd, uid, gid, callback)#