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
  • i8, int8
  • u8, uint8, bool, char
  • i16, int16
  • u16, uint16
  • i32, int32
  • u32, uint32
  • i64, int64
  • u64, uint64
  • f32, float
  • f64, double
  • 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:

  • lib {DynamicLibrary} The loaded library handle.
  • functions <Object> Callable wrappers for the requested symbols.

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 } from 'node:ffi';

{
  using handle = dlopen('./mylib.so', {
    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 } from 'node:ffi';

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

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

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

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

ffi.dlclose(handle)#

  • handle {DynamicLibrary}

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 } = require('node:ffi');

const lib = new DynamicLibrary('./mylib.so');
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 } from 'node:ffi';

{
  using lib = new DynamicLibrary('./mylib.so');
  // 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 } = require('node:ffi');

const lib = new DynamicLibrary('./mylib.so');
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 } = require('node:ffi');

const lib = new DynamicLibrary('./mylib.so');

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.

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.

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.

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><<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><<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.

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 exist. data can be a string or 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.

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').

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)#

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

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

fs.fdatasync(fd, callback)#

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. No arguments other than a possible exception are given to the completion callback.

fs.fstat(fd[, options], callback)#

Invokes the callback with the <fs.Stats> for the file descriptor.

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

fs.fsync(fd, callback)#

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. No arguments other than a possible exception are given to the completion callback.

fs.ftruncate(fd[, len], callback)#

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

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

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

For example, the following program retains only the first four bytes of the file:

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

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

open('temp.txt', 'r+', (err, fd) => {
  if (err) throw err;

  try {
    ftruncate(fd, 4, (err) => {
      closeFd(fd);
      if (err) throw err;
    });
  } catch (err) {
    closeFd(fd);
    if (err) throw err;
  }
});
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.

fs.futimes(fd, atime, mtime, callback)#

Change the file system timestamps of the object referenced by the supplied file descriptor. See fs.utimes().

fs.glob(pattern[, options], callback)#

  • 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.
    • 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.
  • callback <Function>

  • Retrieves the files matching the specified pattern.

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

import { glob } from 'node:fs';

glob('**/*.js', (err, matches) => {
  if (err) throw err;
  console.log(matches);
});
const { glob } = require('node:fs');

glob('**/*.js', (err, matches) => {
  if (err) throw err;
  console.log(matches);
});
javascript

fs.lchmod(path, mode, callback)#

Stability: 0 - Deprecated

Changes the permissions on a symbolic link. No arguments other than a possible exception are given to the completion callback.

This method is only implemented on macOS.

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

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

Set the owner of the symbolic link. No arguments other than a possible exception are given to the completion callback.

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

fs.lutimes(path, atime, mtime, callback)#

Changes the access and modification times of a file in the same way as fs.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.

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

fs.link(existingPath, newPath, callback)#

Creates a new link from the existingPath to the newPath. See the POSIX link(2) documentation for more detail. No arguments other than a possible exception are given to the completion callback.

fs.lstat(path[, options], callback)#

Retrieves the <fs.Stats> for the symbolic link referred to by the path. The callback gets two arguments (err, stats) where stats is a <fs.Stats> object. lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is stat-ed, not the file that it refers to.

See the POSIX lstat(2) documentation for more details.

fs.mkdir(path[, options], callback)#

Asynchronously creates a directory.

The callback is given a possible exception and, if recursive is true, the first directory path created, (err[, path]). path can still be undefined when recursive is true, if no directory was created (for instance, if it was previously created).

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 fs.mkdir() when path is a directory that exists results in an error only when recursive is false. If recursive is false and the directory exists, an EEXIST error occurs.

import { mkdir } from 'node:fs';

// Create ./tmp/a/apple, regardless of whether ./tmp and ./tmp/a exist.
mkdir('./tmp/a/apple', { recursive: true }, (err) => {
  if (err) throw err;
});
mjs

On Windows, using fs.mkdir() on the root directory even with recursion will result in an error:

import { mkdir } from 'node:fs';

mkdir('/', { recursive: true }, (err) => {
  // => [Error: EPERM: operation not permitted, mkdir 'C:\']
});
mjs

See the POSIX mkdir(2) documentation for more details.

fs.mkdtemp(prefix[, options], callback)#

Creates a unique temporary directory.

Generates six random characters to be appended behind a required prefix to create a unique temporary directory. 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 created directory path is passed as a string to the callback's second parameter.

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';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

mkdtemp(join(tmpdir(), 'foo-'), (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Prints: /tmp/foo-itXde2 or C:\Users\...\AppData\Local\Temp\foo-itXde2
});
mjs

The fs.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).

import { tmpdir } from 'node:os';
import { mkdtemp } from 'node:fs';

// The parent directory for the new temporary directory
const tmpDir = tmpdir();

// This method is *INCORRECT*:
mkdtemp(tmpDir, (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Will print something similar to `/tmpabc123`.
  // A new temporary directory is created at the file system root
  // rather than *within* the /tmp directory.
});

// This method is *CORRECT*:
import { sep } from 'node:path';
mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
  if (err) throw err;
  console.log(directory);
  // Will print something similar to `/tmp/abc123`.
  // A new temporary directory is created within
  // the /tmp directory.
});
mjs

fs.open(path[, flags[, mode]], callback)#

Asynchronous file open. See the POSIX open(2) documentation for more details.

mode sets the file mode (permission and sticky bits), but only if the file was created. On Windows, only the write permission can be manipulated; see fs.chmod().

The callback gets two arguments (err, fd).

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.

Functions based on fs.open() exhibit this behavior as well: fs.writeFile(), fs.readFile(), etc.

fs.openAsBlob(path[, options])#

Returns a <Blob> whose data is backed by the given file.

The file must not be modified after the <Blob> is created. Any modifications will cause reading the <Blob> data to fail with a DOMException error. Synchronous stat operations on the file when the Blob is created, and before each read in order to detect whether the file data has been modified on disk.

import { openAsBlob } from 'node:fs';

const blob = await openAsBlob('the.file.txt');
const ab = await blob.arrayBuffer();
blob.stream();
const { openAsBlob } = require('node:fs');

(async () => {
  const blob = await openAsBlob('the.file.txt');
  const ab = await blob.arrayBuffer();
  blob.stream();
})();
javascript

fs.opendir(path[, options], callback)#

Asynchronously open a directory. See the POSIX opendir(3) documentation for more details.

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.

fs.read(fd, buffer, offset, length, position, callback)#

  • fd <integer>
  • buffer <Buffer> | <TypedArray> | <DataView> The buffer that the data will be written to.
  • offset <integer> The position in buffer to write the data to.
  • length <integer> The number of bytes to read.
  • position <integer> | <bigint> | <null> Specifies where to begin reading from in the file. If position is null or -1 , data will be read from the current file position, and the file position will be updated. If position is a non-negative integer, the file position will be unchanged.
  • callback <Function>

Read data from the file specified by fd.

The callback is given the three arguments, (err, bytesRead, buffer).

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

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesRead and buffer properties.

The fs.read() method reads data from the file specified by the file descriptor (fd). The length argument indicates the maximum number of bytes that Node.js will attempt to read from the kernel. However, the actual number of bytes read (bytesRead) can be lower than the specified length for various reasons.

For example:

  • If the file is shorter than the specified length, bytesRead will be set to the actual number of bytes read.
  • If the file encounters EOF (End of File) before the buffer could be filled, Node.js will read all available bytes until EOF is encountered, and the bytesRead parameter in the callback will indicate the actual number of bytes read, which may be less than the specified length.
  • If the file is on a slow network filesystem or encounters any other issue during reading, bytesRead can be lower than the specified length.

Therefore, when using fs.read(), it's important to check the bytesRead value to determine how many bytes were actually read from the file. Depending on your application logic, you may need to handle cases where bytesRead is lower than the specified length, such as by wrapping the read call in a loop if you require a minimum amount of bytes.

This behavior is similar to the POSIX preadv2 function.

fs.read(fd[, options], callback)#

Similar to the fs.read() function, this version takes an optional options object. If no options object is specified, it will default with the above values.

fs.read(fd, buffer[, options], callback)#

Similar to the fs.read() function, this version takes an optional options object. If no options object is specified, it will default with the above values.

fs.readdir(path[, options], callback)#

Reads the contents of a directory. The callback gets two arguments (err, files) where files is an array of the names of the files in the directory excluding '.' and '..'.

See the POSIX readdir(3) documentation for more details.

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 passed to the callback. If the encoding is set to 'buffer', the filenames returned will be passed as <Buffer> objects.

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

fs.readFile(path[, options], callback)#

Asynchronously reads the entire contents of a file.

import { readFile } from 'node:fs';

readFile('/etc/passwd', (err, data) => {
  if (err) throw err;
  console.log(data);
});
mjs

The callback is passed two arguments (err, data), where data is the contents of the file.

If no encoding is specified, then the raw buffer is returned.

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 callback is called with an error.

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

import { readFile } from 'node:fs';

readFile('/etc/passwd', 'utf8', callback);
mjs

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

import { readFile } from 'node:fs';

// macOS, Linux, and Windows
readFile('<directory>', (err, data) => {
  // => [Error: EISDIR: illegal operation on a directory, read <directory>]
});

//  FreeBSD
readFile('<directory>', (err, data) => {
  // => null, <data>
});
mjs

It is possible to abort an ongoing request using an AbortSignal. If a request is aborted the callback is called with an AbortError:

import { readFile } from 'node:fs';

const controller = new AbortController();
const signal = controller.signal;
readFile(fileInfo[0].name, { signal }, (err, buf) => {
  // ...
});
// When you want to abort the request
controller.abort();
mjs

The fs.readFile() function buffers the entire file. To minimize memory costs, when possible prefer streaming via fs.createReadStream().

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

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

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

const buf = Buffer.alloc(16384);
readFile('/path/to/file', { buffer: buf }, (err, data) => {
  if (err) throw err;
  console.log(data); // 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';

readFile('/path/to/file', {
  buffer: (size) => Buffer.alloc(size),
}, (err, data) => {
  if (err) throw err;
  console.log(data);
});
mjs
File descriptors#
  1. Any specified file descriptor has to support reading.
  2. If a file descriptor is specified as the path, it will not be closed automatically.
  3. The reading will begin at the current position. For example, if the file already had 'Hello World' and six bytes are read with the file descriptor, the call to fs.readFile() with the same file descriptor, would give 'World', rather than 'Hello World'.
Performance Considerations#

The fs.readFile() method asynchronously reads the contents of a file into memory one chunk at a time, allowing the event loop to turn between each chunk. This allows the read operation to have less impact on other activity that may be using the underlying libuv thread pool but means that it will take longer to read a complete file into memory.

The additional read overhead can vary broadly on different systems and depends on the type of file being read. If the file type is not a regular file (a pipe for instance) and Node.js is unable to determine an actual file size, each read operation will load on 64 KiB of data. For regular files, each read will process 512 KiB of data.

For applications that require as-fast-as-possible reading of file contents, it is better to use fs.read() directly and for application code to manage reading the full contents of the file itself.

The Node.js GitHub issue #25741 provides more information and a detailed analysis on the performance of fs.readFile() for multiple file sizes in different Node.js versions.

fs.readlink(path[, options], callback)#

Reads the contents of the symbolic link referred to by path. The callback gets two arguments (err, linkString).

See the POSIX readlink(2) documentation for more details.

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 passed to the callback. If the encoding is set to 'buffer', the link path returned will be passed as a <Buffer> object.

fs.readv(fd, buffers[, position], callback)#

Read from a file specified by fd and write to an array of ArrayBufferViews using readv().

position is the offset from the beginning of the file from where data should be read. If typeof position !== 'number', the data will be read from the current position.

The callback will be given three arguments: err, bytesRead, and buffers. bytesRead is how many bytes were read from the file.

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesRead and buffers properties.

fs.realpath(path[, options], callback)#

Asynchronously computes the canonical pathname by resolving ., .., and symbolic links.

A canonical pathname is not necessarily unique. Hard links and bind mounts can expose a file system entity through many pathnames.

This function behaves like realpath(3), with some exceptions:

  1. No case conversion is performed on case-insensitive file systems.

  2. The maximum number of symbolic links is platform-independent and generally (much) higher than what the native realpath(3) implementation supports.

The callback gets two arguments (err, resolvedPath). May use process.cwd to resolve relative paths.

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 passed to the callback. If the encoding is set to 'buffer', the path returned will be passed as a <Buffer> object.

If path resolves to a socket or a pipe, the function will return a system dependent name for that object.

A path that does not exist results in an ENOENT error. error.path is the absolute file path.

fs.realpath.native(path[, options], callback)#

Asynchronous realpath(3).

The callback gets two arguments (err, resolvedPath).

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 passed to the callback. 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.

fs.rename(oldPath, newPath, callback)#

Asynchronously rename file at oldPath to the pathname provided as newPath. In the case that newPath already exists, it will be overwritten. If there is a directory at newPath, an error will be raised instead. No arguments other than a possible exception are given to the completion callback.

See also: rename(2).

import { rename } from 'node:fs';

rename('oldFile.txt', 'newFile.txt', (err) => {
  if (err) throw err;
  console.log('Rename complete!');
});
mjs

fs.rmdir(path[, options], callback)#

  • 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.
  • callback <Function>

Asynchronous rmdir(2). No arguments other than a possible exception are given to the completion callback.

Using fs.rmdir() on a file (not a directory) results in an ENOENT error on Windows and an ENOTDIR error on POSIX.

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

fs.rm(path[, options], callback)#

  • 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 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.
  • callback <Function>

Asynchronously removes files and directories (modeled on the standard POSIX rm utility). No arguments other than a possible exception are given to the completion callback.

fs.stat(path[, options], callback)#

Asynchronous stat(2). The callback gets two arguments (err, stats) where stats is an <fs.Stats> object.

In case of an error, the err.code will be one of Common System Errors.

fs.stat() follows symbolic links. Use fs.lstat() to look at the links themselves.

Using fs.stat() to check for the existence of a file before calling fs.open(), fs.readFile(), or fs.writeFile() is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available.

To check if a file exists without manipulating it afterwards, fs.access() is recommended.

For example, given the following directory structure:

- txtDir
-- file.txt
- app.js
text

The next program will check for the stats of the given paths:

import { stat } from 'node:fs';

const pathsToCheck = ['./txtDir', './txtDir/file.txt'];

for (let i = 0; i < pathsToCheck.length; i++) {
  stat(pathsToCheck[i], (err, stats) => {
    console.log(stats.isDirectory());
    console.log(stats);
  });
}
mjs

The resulting output will resemble:

true
Stats {
  dev: 16777220,
  mode: 16877,
  nlink: 3,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214262,
  size: 96,
  blocks: 0,
  atimeMs: 1561174653071.963,
  mtimeMs: 1561174614583.3518,
  ctimeMs: 1561174626623.5366,
  birthtimeMs: 1561174126937.2893,
  atime: 2019-06-22T03:37:33.072Z,
  mtime: 2019-06-22T03:36:54.583Z,
  ctime: 2019-06-22T03:37:06.624Z,
  birthtime: 2019-06-22T03:28:46.937Z,
  atimeInstant: 2019-06-22T03:37:33.071963Z,
  mtimeInstant: 2019-06-22T03:36:54.5833518Z,
  ctimeInstant: 2019-06-22T03:37:06.6235366Z,
  birthtimeInstant: 2019-06-22T03:28:46.9372893Z
}
false
Stats {
  dev: 16777220,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14214074,
  size: 8,
  blocks: 8,
  atimeMs: 1561174616618.8555,
  mtimeMs: 1561174614584,
  ctimeMs: 1561174614583.8145,
  birthtimeMs: 1561174007710.7478,
  atime: 2019-06-22T03:36:56.619Z,
  mtime: 2019-06-22T03:36:54.584Z,
  ctime: 2019-06-22T03:36:54.584Z,
  birthtime: 2019-06-22T03:26:47.711Z,
  atimeInstant: 2019-06-22T03:36:56.6188555Z,
  mtimeInstant: 2019-06-22T03:36:54.584Z,
  ctimeInstant: 2019-06-22T03:36:54.5838145Z,
  birthtimeInstant: 2019-06-22T03:26:47.7107478Z
}
console

fs.statfs(path[, options], callback)#

Asynchronous statfs(2). Returns information about the mounted file system which contains path. The callback gets two arguments (err, stats) where stats is an <fs.StatFs> object.

In case of an error, the err.code will be one of Common System Errors.

fs.symlink(target, path[, type], callback)#

Creates the link called path pointing to target. No arguments other than a possible exception are given to the completion callback.

See the POSIX symlink(2) documentation for more details.

The type argument is only available on Windows and ignored on other platforms. It can be set to '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.

Relative targets are relative to the link's parent directory.

import { symlink } from 'node:fs';

symlink('./mew', './mewtwo', callback);
mjs

The above example creates a symbolic link mewtwo which points to mew in the same directory:

$ tree .
.
├── mew
└── mewtwo -> ./mew
bash

fs.truncate(path[, len], callback)#

Truncates the file. No arguments other than a possible exception are given to the completion callback. A file descriptor can also be passed as the first argument. In this case, fs.ftruncate() is called.

import { truncate } from 'node:fs';
// Assuming that 'path/file.txt' is a regular file.
truncate('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was truncated');
});
const { truncate } = require('node:fs');
// Assuming that 'path/file.txt' is a regular file.
truncate('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was truncated');
});
javascript

Passing a file descriptor is deprecated and may result in an error being thrown in the future.

See the POSIX truncate(2) documentation for more details.

fs.unlink(path, callback)#

Asynchronously removes a file or symbolic link. No arguments other than a possible exception are given to the completion callback.

import { unlink } from 'node:fs';
// Assuming that 'path/file.txt' is a regular file.
unlink('path/file.txt', (err) => {
  if (err) throw err;
  console.log('path/file.txt was deleted');
});
mjs

fs.unlink() will not work on a directory, empty or otherwise. To remove a directory, use fs.rmdir().

See the POSIX unlink(2) documentation for more details.

fs.unwatchFile(filename[, listener])#

Stop watching for changes on filename. If listener is specified, only that particular listener is removed. Otherwise, all listeners are removed, effectively stopping watching of filename.

Calling fs.unwatchFile() with a filename that is not being watched is a no-op, not an error.

Using fs.watch() is more efficient than fs.watchFile() and fs.unwatchFile(). fs.watch() should be used instead of fs.watchFile() and fs.unwatchFile() when possible.

fs.utimes(path, atime, mtime, callback)#

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 in seconds, 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.

fs.watch(filename[, options][, listener])#

  • 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> allows closing the watcher with an AbortSignal.
    • throwIfNoEntry <boolean> Indicates whether an exception should be thrown when the path does not exist. Default: true.
    • 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.
  • listener <Function> | <undefined> Default: undefined
  • Returns: <fs.FSWatcher>

Watch for changes on filename, where filename is either a file or a directory.

The second argument is optional. If options is provided as a string, it specifies the encoding. Otherwise options should be passed as an object.

The listener callback gets two arguments (eventType, filename). eventType is either 'rename' or 'change', and filename is the name of the file which triggered the event.

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

The listener callback is attached to the 'change' event fired by <fs.FSWatcher>, but it is not the same thing as the 'change' value of eventType.

If a signal is passed, aborting the corresponding AbortController will close the returned <fs.FSWatcher>.

Caveats#

The fs.watch API is not 100% consistent across platforms, and is unavailable in some situations.

On Windows, no events will be emitted if the watched directory is moved or renamed. An EPERM error is reported when the watched directory is deleted.

The fs.watch API does not provide any protection with respect to malicious actions on the file system. For example, on Windows it is implemented by monitoring changes in a directory versus specific files. This allows substitution of a file and fs reporting changes on the new file with the same filename.

Availability#

This feature depends on the underlying operating system providing a way to be notified of file system changes.

  • On Linux systems, this uses inotify(7).
  • On BSD systems, this uses kqueue(2).
  • On macOS, this uses kqueue(2) for files and FSEvents for directories.
  • On SunOS systems (including Solaris and SmartOS), this uses event ports.
  • On Windows systems, this feature depends on ReadDirectoryChangesW.
  • On AIX systems, this feature depends on AHAFS, which must be enabled.
  • On IBM i systems, this feature is not supported.

If the underlying functionality is not available for some reason, then fs.watch() will not be able to function and may throw an exception. For example, watching files or directories can be unreliable, and in some cases impossible, on network file systems (NFS, SMB, etc) or host file systems when using virtualization software such as Vagrant or Docker.

It is still possible to use fs.watchFile(), which uses stat polling, but this method is slower and less reliable.

Inodes#

On Linux and macOS systems, fs.watch() resolves the path to an inode and watches the inode. If the watched path is deleted and recreated, it is assigned a new inode. The watch will emit an event for the delete but will continue watching the original inode. Events for the new inode will not be emitted. This is expected behavior.

AIX files retain the same inode for the lifetime of a file. Saving and closing a watched file on AIX will result in two notifications (one for adding new content, and one for truncation).

Filename argument#

Providing filename argument in the callback is only supported on Linux, macOS, Windows, and AIX. Even on supported platforms, filename is not always guaranteed to be provided. Therefore, don't assume that filename argument is always provided in the callback, and have some fallback logic if it is null.

import { watch } from 'node:fs';
watch('somedir', (eventType, filename) => {
  console.log(`event type is: ${eventType}`);
  if (filename) {
    console.log(`filename provided: ${filename}`);
  } else {
    console.log('filename not provided');
  }
});
mjs

fs.watchFile(filename[, options], listener)#

Watch for changes on filename. The callback listener will be called each time the file is accessed.

The options argument may be omitted. If provided, it should be an object. The options object may contain a boolean named persistent that indicates whether the process should continue to run as long as files are being watched. The options object may specify an interval property indicating how often the target should be polled in milliseconds.

The listener gets two arguments the current stat object and the previous stat object:

import { watchFile } from 'node:fs';

watchFile('message.text', (curr, prev) => {
  console.log(`the current mtime is: ${curr.mtime}`);
  console.log(`the previous mtime was: ${prev.mtime}`);
});
mjs

These stat objects are instances of fs.Stat. If the bigint option is true, the numeric values in these objects are specified as BigInts.

To be notified when the file was modified, not just accessed, it is necessary to compare curr.mtimeMs and prev.mtimeMs.

When an fs.watchFile operation results in an ENOENT error, it will invoke the listener once, with all the fields zeroed (or, for dates, the Unix Epoch). If the file is created later on, the listener will be called again, with the latest stat objects. This is a change in functionality since v0.10.

Using fs.watch() is more efficient than fs.watchFile and fs.unwatchFile. fs.watch should be used instead of fs.watchFile and fs.unwatchFile when possible.

When a file being watched by fs.watchFile() disappears and reappears, then the contents of previous in the second callback event (the file's reappearance) will be the same as the contents of previous in the first callback event (its disappearance).

This happens when:

  • the file is deleted, followed by a restore
  • the file is renamed and then renamed a second time back to its original name

fs.write(fd, buffer, offset[, length[, position]], callback)#

Write buffer to the file specified by fd.

offset determines the part of the buffer to be written, and length is an integer specifying the number of bytes to write.

position refers to the offset from the beginning of the file where this data should be written. If typeof position !== 'number', the data will be written at the current position. See pwrite(2).

The callback will be given three arguments (err, bytesWritten, buffer) where bytesWritten specifies how many bytes were written from buffer.

If this method is invoked as its util.promisify()ed version, it returns a promise for an Object with bytesWritten and buffer properties.

It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

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.

fs.write(fd, buffer[, options], callback)#

Write buffer to the file specified by fd.

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

fs.write(fd, string[, position[, encoding]], callback)#

Write string to the file specified by fd. If string is not a string, an exception is thrown.

position refers to the offset from the beginning of the file where this data should be written. If typeof position !== 'number' the data will be written at the current position. See pwrite(2).

encoding is the expected string encoding.

The callback will receive the arguments (err, written, string) where written specifies how many bytes the passed string required to be written. Bytes written is not necessarily the same as string characters written. See Buffer.byteLength.

It is unsafe to use fs.write() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

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.

On Windows, if the file descriptor is connected to the console (e.g. fd == 1 or stdout) a string containing non-ASCII characters will not be rendered properly by default, regardless of the encoding used. It is possible to configure the console to render UTF-8 properly by changing the active codepage with the chcp 65001 command. See the chcp docs for more details.

fs.writeFile(file, data[, options], callback)#

When file is a filename, asynchronously writes data to the file, replacing the file if it already exists. data can be a string or a buffer.

When file is a file descriptor, the behavior is similar to calling fs.write() directly (which is recommended). See the notes below on using a file descriptor.

The encoding option is ignored if data is a buffer.

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

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

const data = new Uint8Array(Buffer.from('Hello Node.js'));
writeFile('message.txt', data, (err) => {
  if (err) throw err;
  console.log('The file has been saved!');
});
mjs

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

import { writeFile } from 'node:fs';

writeFile('message.txt', 'Hello Node.js', 'utf8', callback);
mjs

It is unsafe to use fs.writeFile() multiple times on the same file without waiting for the callback. For this scenario, fs.createWriteStream() is recommended.

Similarly to fs.readFile - fs.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().

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

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

const controller = new AbortController();
const { signal } = controller;
const data = new Uint8Array(Buffer.from('Hello Node.js'));
writeFile('message.txt', data, { signal }, (err) => {
  // When a request is aborted - the callback is called with an AbortError
});
// When the request should be aborted
controller.abort();
mjs

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

Using fs.writeFile() with file descriptors#

When file is a file descriptor, the behavior is almost identical to directly calling fs.write() like:

import { write } from 'node:fs';
import { Buffer } from 'node:buffer';

write(fd, Buffer.from(data, options.encoding), callback);
mjs

The difference from directly calling fs.write() is that under some unusual conditions, fs.write() might write only part of the buffer and need to be retried to write the remaining data, whereas fs.writeFile() retries until the data is entirely written (or an error occurs).

The implications of this are a common source of confusion. In the file descriptor case, the file is not replaced! The data is not necessarily written to the beginning of the file, and the file's original data may remain before and/or after the newly written data.

For example, if fs.writeFile() is called twice in a row, first to write the string 'Hello', then to write the string ', World', the file would contain 'Hello, World', and might contain some of the file's original data (depending on the size of the original file, and the position of the file descriptor). If a file name had been used instead of a descriptor, the file would be guaranteed to contain only ', World'.

fs.writev(fd, buffers[, position], callback)#

Write an array of ArrayBufferViews to the file specified by fd using writev().

position is the offset from the beginning of the file where this data should be written. If typeof position !== 'number', the data will be written at the current position.

The callback will be given three arguments: err, bytesWritten, and buffers. bytesWritten is how many bytes were written from buffers.

If this method is util.promisify()ed, it returns a promise for an Object with bytesWritten and buffers properties.

It is unsafe to use fs.writev() multiple times on the same file without waiting for the callback. For this scenario, use fs.createWriteStream().

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.

Synchronous API#

The synchronous APIs perform all operations synchronously, blocking the event loop until the operation completes or fails.

fs.accessSync(path[, mode])#

Synchronously 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 any of the accessibility checks fail, an Error will be thrown. Otherwise, the method will return undefined.

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

try {
  accessSync('etc/passwd', constants.R_OK | constants.W_OK);
  console.log('can read/write');
} catch (err) {
  console.error('no access!');
}
mjs

fs.appendFileSync(path, data[, options])#

Synchronously 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 { appendFileSync } from 'node:fs';

try {
  appendFileSync('message.txt', 'data to append');
  console.log('The "data to append" was appended to file!');
} catch (err) {
  /* Handle the error */
}
mjs

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

import { appendFileSync } from 'node:fs';

appendFileSync('message.txt', 'data to append', 'utf8');
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 { openSync, closeSync, appendFileSync } from 'node:fs';

let fd;

try {
  fd = openSync('message.txt', 'a');
  appendFileSync(fd, 'data to append', 'utf8');
} catch (err) {
  /* Handle the error */
} finally {
  if (fd !== undefined)
    closeSync(fd);
}
mjs

fs.chmodSync(path, mode)#

For detailed information, see the documentation of the asynchronous version of this API: fs.chmod().

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

fs.chownSync(path, uid, gid)#

Synchronously changes owner and group of a file. Returns undefined. This is the synchronous version of fs.chown().

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

fs.closeSync(fd)#

Closes the file descriptor. Returns undefined.

Calling fs.closeSync() 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.copyFileSync(src, dest[, mode])#

Synchronously copies src to dest. By default, dest is overwritten if it already exists. Returns undefined. 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 { copyFileSync, constants } from 'node:fs';

// destination.txt will be created or overwritten by default.
copyFileSync('source.txt', 'destination.txt');
console.log('source.txt was copied to destination.txt');

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

fs.cpSync(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. Default: undefined
      • src <string> source path to copy.
      • dest <string> destination path to copy to.
      • Returns: <boolean> Any non-Promise value that is coercible to boolean.
    • 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.copyFileSync().
    • 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

Synchronously 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.existsSync(path)#

Returns true if the path exists, false otherwise.

For detailed information, see the documentation of the asynchronous version of this API: fs.exists().

fs.exists() is deprecated, but fs.existsSync() is not. The callback parameter to fs.exists() accepts parameters that are inconsistent with other Node.js callbacks. fs.existsSync() does not use a callback.

import { existsSync } from 'node:fs';

if (existsSync('/etc/passwd'))
  console.log('The path exists.');
mjs

fs.fchmodSync(fd, mode)#

Sets the permissions on the file. Returns undefined.

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

fs.fchownSync(fd, uid, gid)#

Sets the owner of the file. Returns undefined.

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

fs.fdatasyncSync(fd)#

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. Returns undefined.

fs.fstatSync(fd[, options])#

Retrieves the <fs.Stats> for the file descriptor.

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

fs.fsyncSync(fd)#

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. Returns undefined.

fs.ftruncateSync(fd[, len])#

Truncates the file descriptor. Returns undefined.

For detailed information, see the documentation of the asynchronous version of this API: fs.ftruncate().

fs.futimesSync(fd, atime, mtime)#

Synchronous version of fs.futimes(). Returns undefined.

fs.globSync(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.
    • 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: <string>[] paths of files that match the pattern.

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

import { globSync } from 'node:fs';

console.log(globSync('**/*.js'));
const { globSync } = require('node:fs');

console.log(globSync('**/*.js'));
javascript

fs.lchmodSync(path, mode)#

Stability: 0 - Deprecated

Changes the permissions on a symbolic link. Returns undefined.

This method is only implemented on macOS.

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

fs.lchownSync(path, uid, gid)#

Set the owner for the path. Returns undefined.

See the POSIX lchown(2) documentation for more details.

fs.lutimesSync(path, atime, mtime)#

Change the file system timestamps of the symbolic link referenced by path. Returns undefined, or throws an exception when parameters are incorrect or the operation fails. This is the synchronous version of fs.lutimes().

fs.linkSync(existingPath, newPath)#

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

fs.lstatSync(path[, options])#

Retrieves the <fs.Stats> for the symbolic link referred to by path.

See the POSIX lstat(2) documentation for more details.

fs.mkdirSync(path[, options])#

Synchronously creates a directory. Returns undefined, or if recursive is true, the first directory path created. This is the synchronous version of fs.mkdir().

See the POSIX mkdir(2) documentation for more details.

fs.mkdtempSync(prefix[, options])#

Returns the created directory path.

For detailed information, see the documentation of the asynchronous version of this API: fs.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.

fs.mkdtempDisposableSync(prefix[, options])#

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

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

There is no callback-based version of this API because it is designed for use with the using syntax.

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

fs.opendirSync(path[, options])#

  • path <string> | <Buffer> | <URL>
  • options <Object>
    • encoding <string> | <null> Default: 'utf8'
    • bufferSize <number> Number of directory entries that are buffered internally when reading from the directory. Higher values lead to better performance but higher memory usage. Default: 32
    • recursive <boolean> Default: false
  • Returns: <fs.Dir>

Synchronously open a directory. See opendir(3).

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.

fs.openSync(path[, flags[, mode]])#

Returns an integer representing the file descriptor.

For detailed information, see the documentation of the asynchronous version of this API: fs.open().

fs.readdirSync(path[, options])#

Reads the contents of the directory.

See the POSIX readdir(3) documentation for more details.

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 returned. If the encoding is set to 'buffer', the filenames returned will be passed as <Buffer> objects.

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

fs.readFileSync(path[, options])#

Returns the contents of the path.

For detailed information, see the documentation of the asynchronous version of this API: fs.readFile().

If the encoding option is specified then this function returns a string. Otherwise it returns a buffer.

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, an error will be thrown.

Similar to fs.readFile(), when the path is a directory, the behavior of fs.readFileSync() is platform-specific.

import { readFileSync } from 'node:fs';

// macOS, Linux, and Windows
readFileSync('<directory>');
// => [Error: EISDIR: illegal operation on a directory, read <directory>]

//  FreeBSD
readFileSync('<directory>'); // => <data>
mjs

fs.readlinkSync(path[, options])#

Returns the symbolic link's string value.

See the POSIX readlink(2) documentation for more details.

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.

fs.readSync(fd, buffer, offset, length[, position])#

Returns the number of bytesRead.

For detailed information, see the documentation of the asynchronous version of this API: fs.read().

fs.readSync(fd, buffer[, options])#

Returns the number of bytesRead.

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

For detailed information, see the documentation of the asynchronous version of this API: fs.read().

fs.readvSync(fd, buffers[, position])#

For detailed information, see the documentation of the asynchronous version of this API: fs.readv().

fs.realpathSync(path[, options])#

Returns the resolved pathname.

For detailed information, see the documentation of the asynchronous version of this API: fs.realpath().

fs.realpathSync.native(path[, options])#

Synchronous realpath(3).

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 returned. 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.

fs.renameSync(oldPath, newPath)#

Renames the file from oldPath to newPath. Returns undefined.

See the POSIX rename(2) documentation for more details.

fs.rmdirSync(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.

Synchronous rmdir(2). Returns undefined.

Using fs.rmdirSync() on a file (not a directory) results in an ENOENT error on Windows and an ENOTDIR error on POSIX.

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

fs.rmSync(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.

Synchronously removes files and directories (modeled on the standard POSIX rm utility). Returns undefined.

fs.statSync(path[, options])#

Retrieves the <fs.Stats> for the path.

fs.statfsSync(path[, options])#

Synchronous statfs(2). Returns information about the mounted file system which contains path.

In case of an error, the err.code will be one of Common System Errors.

fs.symlinkSync(target, path[, type])#

For detailed information, see the documentation of the asynchronous version of this API: fs.symlink().

fs.truncateSync(path[, len])#

Truncates the file. Returns undefined. A file descriptor can also be passed as the first argument. In this case, fs.ftruncateSync() is called.

Passing a file descriptor is deprecated and may result in an error being thrown in the future.

fs.unlinkSync(path)#

Synchronous unlink(2). Returns undefined.

fs.utimesSync(path, atime, mtime)#

For detailed information, see the documentation of the asynchronous version of this API: fs.utimes().

fs.writeFileSync(file, data[, options])#

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

For detailed information, see the documentation of the asynchronous version of this API: fs.writeFile().

fs.writeSync(fd, buffer, offset[, length[, position]])#

For detailed information, see the documentation of the asynchronous version of this API: fs.write(fd, buffer...).

fs.writeSync(fd, buffer[, options])#

For detailed information, see the documentation of the asynchronous version of this API: fs.write(fd, buffer...).

fs.writeSync(fd, string[, position[, encoding]])#

For detailed information, see the documentation of the asynchronous version of this API: fs.write(fd, string...).

fs.writevSync(fd, buffers[, position])#

For detailed information, see the documentation of the asynchronous version of this API: fs.writev().

Common Objects#

The common objects are shared by all of the file system API variants (promise, callback, and synchronous).

Class: fs.Dir#

A class representing a directory stream.

Created by fs.opendir(), fs.opendirSync(), or fsPromises.opendir().

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.

dir.close()#

Asynchronously close the directory's underlying resource handle. Subsequent reads will result in errors.

A promise is returned that will be fulfilled after the resource has been closed.

dir.close(callback)#

Asynchronously close the directory's underlying resource handle. Subsequent reads will result in errors.

The callback will be called after the resource handle has been closed.

dir.closeSync()#

Synchronously close the directory's underlying resource handle. Subsequent reads will result in errors.

dir.path#

The read-only path of this directory as was provided to fs.opendir(), fs.opendirSync(), or fsPromises.opendir().

dir.read()#

Asynchronously read the next directory entry via readdir(3) as an <fs.Dirent>.

A promise is returned that will be fulfilled with an <fs.Dirent>, or null if there are no more directory entries to read.

Directory entries returned by this function are in no particular order as provided by the operating system's underlying directory mechanisms. Entries added or removed while iterating over the directory might not be included in the iteration results.

dir.read(callback)#

Asynchronously read the next directory entry via readdir(3) as an <fs.Dirent>.

After the read is completed, the callback will be called with an <fs.Dirent>, or null if there are no more directory entries to read.

Directory entries returned by this function are in no particular order as provided by the operating system's underlying directory mechanisms. Entries added or removed while iterating over the directory might not be included in the iteration results.

dir.readSync()#

Synchronously read the next directory entry as an <fs.Dirent>. See the POSIX readdir(3) documentation for more detail.

If there are no more directory entries to read, null will be returned.

Directory entries returned by this function are in no particular order as provided by the operating system's underlying directory mechanisms. Entries added or removed while iterating over the directory might not be included in the iteration results.

dir[Symbol.asyncIterator]()#

Asynchronously iterates over the directory until all entries have been read. Refer to the POSIX readdir(3) documentation for more detail.

Entries returned by the async iterator are always an <fs.Dirent>. The null case from dir.read() is handled internally.

See <fs.Dir> for an example.

Directory entries returned by this iterator are in no particular order as provided by the operating system's underlying directory mechanisms. Entries added or removed while iterating over the directory might not be included in the iteration results.

dir[Symbol.asyncDispose]()#

Calls dir.close() if the directory handle is open, and returns a promise that fulfills when disposal is complete.

dir[Symbol.dispose]()#

Calls dir.closeSync() if the directory handle is open, and returns undefined.

Class: fs.Dirent#

A representation of a directory entry, which can be a file or a subdirectory within the directory, as returned by reading from an <fs.Dir>. The directory entry is a combination of the file name and file type pairs.

Additionally, when fs.readdir() or fs.readdirSync() is called with the withFileTypes option set to true, the resulting array is filled with <fs.Dirent> objects, rather than strings or <Buffer>s.

dirent.isBlockDevice()#

Returns true if the <fs.Dirent> object describes a block device.

dirent.isCharacterDevice()#

Returns true if the <fs.Dirent> object describes a character device.

dirent.isDirectory()#

Returns true if the <fs.Dirent> object describes a file system directory.

dirent.isFIFO()#

Returns true if the <fs.Dirent> object describes a first-in-first-out (FIFO) pipe.

dirent.isFile()#

Returns true if the <fs.Dirent> object describes a regular file.

dirent.isSocket()#

Returns true if the <fs.Dirent> object describes a socket.

dirent.isSymbolicLink()#

Returns true if the <fs.Dirent> object describes a symbolic link.

dirent.name#

The file name that this <fs.Dirent> object refers to. The type of this value is determined by the options.encoding passed to fs.readdir() or fs.readdirSync().

dirent.parentPath#

The path to the parent directory of the file this <fs.Dirent> object refers to.

Class: fs.FSWatcher#

A successful call to fs.watch() method will return a new <fs.FSWatcher> object.

All <fs.FSWatcher> objects emit a 'change' event whenever a specific watched file is modified.

Event: 'change'#
  • eventType <string> The type of change event that has occurred
  • filename <string> | <Buffer> The filename that changed (if relevant/available)

Emitted when something changes in a watched directory or file. See more details in fs.watch().

The filename argument may not be provided depending on operating system support. If filename is provided, it will be provided as a <Buffer> if fs.watch() is called with its encoding option set to 'buffer', otherwise filename will be a UTF-8 string.

import { watch } from 'node:fs';
// Example when handled through fs.watch() listener
watch('./tmp', { encoding: 'buffer' }, (eventType, filename) => {
  if (filename) {
    console.log(filename);
    // Prints: <Buffer ...>
  }
});
mjs
Event: 'close'#

Emitted when the watcher stops watching for changes. The closed <fs.FSWatcher> object is no longer usable in the event handler.

Event: 'error'#

Emitted when an error occurs while watching the file. The errored <fs.FSWatcher> object is no longer usable in the event handler.

watcher.close()#

Stop watching for changes on the given <fs.FSWatcher>. Once stopped, the <fs.FSWatcher> object is no longer usable.

watcher.ref()#

When called, requests that the Node.js event loop not exit so long as the <fs.FSWatcher> is active. Calling watcher.ref() multiple times will have no effect.

By default, all <fs.FSWatcher> objects are "ref'ed", making it normally unnecessary to call watcher.ref() unless watcher.unref() had been called previously.

watcher.unref()#

When called, the active <fs.FSWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.FSWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.

Class: fs.StatWatcher#

A successful call to fs.watchFile() method will return a new <fs.StatWatcher> object.

watcher.ref()#

When called, requests that the Node.js event loop not exit so long as the <fs.StatWatcher> is active. Calling watcher.ref() multiple times will have no effect.

By default, all <fs.StatWatcher> objects are "ref'ed", making it normally unnecessary to call watcher.ref() unless watcher.unref() had been called previously.

watcher.unref()#

When called, the active <fs.StatWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.StatWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.

Class: fs.ReadStream#

Instances of <fs.ReadStream> cannot be constructed directly. They are created and returned using the fs.createReadStream() function.

Event: 'close'#

Emitted when the <fs.ReadStream>'s underlying file descriptor has been closed.

Event: 'open'#

Emitted when the <fs.ReadStream>'s file descriptor has been opened.

Event: 'ready'#

Emitted when the <fs.ReadStream> is ready to be used.

Fires immediately after 'open'.

readStream.bytesRead#

The number of bytes that have been read so far.

readStream.path#

The path to the file the stream is reading from as specified in the first argument to fs.createReadStream(). If path is passed as a string, then readStream.path will be a string. If path is passed as a <Buffer>, then readStream.path will be a <Buffer>. If fd is specified, then readStream.path will be undefined.

readStream.pending#

This property is true if the underlying file has not been opened yet, i.e. before the 'ready' event is emitted.

Class: fs.Stats#

A <fs.Stats> object provides information about a file.

Objects returned from fs.stat(), fs.lstat(), fs.fstat(), and their synchronous counterparts are of this type. If bigint in the options passed to those methods is true, the numeric values will be bigint instead of number, and the object will contain additional nanosecond-precision properties suffixed with Ns. Stat objects are not to be created directly using the new keyword.

Stats {
  dev: 2114,
  ino: 48064969,
  mode: 33188,
  nlink: 1,
  uid: 85,
  gid: 100,
  rdev: 0,
  size: 527,
  blksize: 4096,
  blocks: 8,
  atimeMs: 1318289051000.1,
  mtimeMs: 1318289051000.1,
  ctimeMs: 1318289051000.1,
  birthtimeMs: 1318289051000.1,

  // Instances of Date
  atime: Mon, 10 Oct 2011 23:24:11 GMT,
  mtime: Mon, 10 Oct 2011 23:24:11 GMT,
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT,

  // Instances of Temporal.Instant
  atimeInstant: 2011-10-10T23:24:11.0001Z,
  mtimeInstant: 2011-10-10T23:24:11.0001Z,
  ctimeInstant: 2011-10-10T23:24:11.0001Z,
  birthtimeInstant: 2011-10-10T23:24:11.0001Z
}
console

bigint version:

BigIntStats {
  dev: 2114n,
  ino: 48064969n,
  mode: 33188n,
  nlink: 1n,
  uid: 85n,
  gid: 100n,
  rdev: 0n,
  size: 527n,
  blksize: 4096n,
  blocks: 8n,
  atimeMs: 1318289051000n,
  mtimeMs: 1318289051000n,
  ctimeMs: 1318289051000n,
  birthtimeMs: 1318289051000n,
  atimeNs: 1318289051000000000n,
  mtimeNs: 1318289051000000000n,
  ctimeNs: 1318289051000000000n,
  birthtimeNs: 1318289051000000000n,

  // Instances of Date
  atime: Mon, 10 Oct 2011 23:24:11 GMT,
  mtime: Mon, 10 Oct 2011 23:24:11 GMT,
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT,

  // Instances of Temporal.Instant
  atimeInstant: 2011-10-10T23:24:11Z,
  mtimeInstant: 2011-10-10T23:24:11Z,
  ctimeInstant: 2011-10-10T23:24:11Z,
  birthtimeInstant: 2011-10-10T23:24:11Z
}
console
stats.isBlockDevice()#

Returns true if the <fs.Stats> object describes a block device.

stats.isCharacterDevice()#

Returns true if the <fs.Stats> object describes a character device.

stats.isDirectory()#

Returns true if the <fs.Stats> object describes a file system directory.

If the <fs.Stats> object was obtained from calling fs.lstat() on a symbolic link which resolves to a directory, this method will return false. This is because fs.lstat() returns information about a symbolic link itself and not the path it resolves to.

stats.isFIFO()#

Returns true if the <fs.Stats> object describes a first-in-first-out (FIFO) pipe.

stats.isFile()#

Returns true if the <fs.Stats> object describes a regular file.

stats.isSocket()#

Returns true if the <fs.Stats> object describes a socket.

stats.isSymbolicLink()#

Returns true if the <fs.Stats> object describes a symbolic link.

This method is only valid when using fs.lstat().

stats.dev#

The numeric identifier of the device containing the file.

stats.ino#

The file system specific "Inode" number for the file.

stats.mode#

A bit-field describing the file type and mode.

stats.nlink#

The number of hard-links that exist for the file.

stats.uid#

The numeric user identifier of the user that owns the file (POSIX).

stats.gid#

The numeric group identifier of the group that owns the file (POSIX).

stats.rdev#

A numeric device identifier if the file represents a device.

stats.size#

The size of the file in bytes.

If the underlying file system does not support getting the size of the file, this will be 0.

stats.blksize#

The file system block size for i/o operations.

stats.blocks#

The number of blocks allocated for this file.

stats.atimeMs#

The timestamp indicating the last time this file was accessed expressed in milliseconds since the POSIX Epoch.

stats.mtimeMs#

The timestamp indicating the last time this file was modified expressed in milliseconds since the POSIX Epoch.

stats.ctimeMs#

The timestamp indicating the last time the file status was changed expressed in milliseconds since the POSIX Epoch.

stats.birthtimeMs#

The timestamp indicating the creation time of this file expressed in milliseconds since the POSIX Epoch.

stats.atimeNs#

Only present when bigint: true is passed into the method that generates the object. The timestamp indicating the last time this file was accessed expressed in nanoseconds since the POSIX Epoch.

stats.mtimeNs#

Only present when bigint: true is passed into the method that generates the object. The timestamp indicating the last time this file was modified expressed in nanoseconds since the POSIX Epoch.

stats.ctimeNs#

Only present when bigint: true is passed into the method that generates the object. The timestamp indicating the last time the file status was changed expressed in nanoseconds since the POSIX Epoch.

stats.birthtimeNs#

Only present when bigint: true is passed into the method that generates the object. The timestamp indicating the creation time of this file expressed in nanoseconds since the POSIX Epoch.

stats.atime#

The timestamp indicating the last time this file was accessed.

stats.mtime#

The timestamp indicating the last time this file was modified.

stats.ctime#

The timestamp indicating the last time the file status was changed.

stats.birthtime#

The timestamp indicating the creation time of this file.

Stat time values#

The atimeMs, mtimeMs, ctimeMs, birthtimeMs properties are numeric values that hold the corresponding times in milliseconds. Their precision is platform specific. When bigint: true is passed into the method that generates the object, the properties will be bigints, otherwise they will be numbers.

The atimeNs, mtimeNs, ctimeNs, birthtimeNs properties are bigints that hold the corresponding times in nanoseconds. They are only present when bigint: true is passed into the method that generates the object. Their precision is platform specific.

atime, mtime, ctime, and birthtime are Date object alternate representations of the various times. The Date and number values are not connected. Assigning a new number value, or mutating the Date value, will not be reflected in the corresponding alternate representation.

The times in the stat object have the following semantics:

  • atime "Access Time": Time when file data last accessed. Changed by the mknod(2), utimes(2), and read(2) system calls.
  • mtime "Modified Time": Time when file data last modified. Changed by the mknod(2), utimes(2), and write(2) system calls.
  • ctime "Change Time": Time when file status was last changed (inode data modification). Changed by the chmod(2), chown(2), link(2), mknod(2), rename(2), unlink(2), utimes(2), read(2), and write(2) system calls.
  • birthtime "Birth Time": Time of file creation. Set once when the file is created. On file systems where birthtime is not available, this field may instead hold either the ctime or 1970-01-01T00:00Z (ie, Unix epoch timestamp 0). This value may be greater than atime or mtime in this case. On Darwin and other FreeBSD variants, also set if the atime is explicitly set to an earlier value than the current birthtime using the utimes(2) system call.

Prior to Node.js 0.12, the ctime held the birthtime on Windows systems. As of 0.12, ctime is not "creation time", and on Unix systems, it never was.

Class: fs.StatFs#

Provides information about a mounted file system.

Objects returned from fs.statfs() and its synchronous counterpart are of this type. If bigint in the options passed to those methods is true, the numeric values will be bigint instead of number.

StatFs {
  type: 1397114950,
  bsize: 4096,
  frsize: 4096,
  blocks: 121938943,
  bfree: 61058895,
  bavail: 61058895,
  files: 999,
  ffree: 1000000
}
console

bigint version:

StatFs {
  type: 1397114950n,
  bsize: 4096n,
  frsize: 4096n,
  blocks: 121938943n,
  bfree: 61058895n,
  bavail: 61058895n,
  files: 999n,
  ffree: 1000000n
}
console
statfs.bavail#

Free blocks available to unprivileged users. Multiply by statfs.bsize to get the number of available bytes.

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

const stats = await statfs('/');
const availableBytes = stats.bsize * stats.bavail;
console.log(`Available space: ${availableBytes} bytes`);
const { statfs } = require('node:fs/promises');

(async () => {
  const stats = await statfs('/');
  const availableBytes = stats.bsize * stats.bavail;
  console.log(`Available space: ${availableBytes} bytes`);
})();
javascript
statfs.bfree#

Free blocks in file system. Multiply by statfs.bsize to get the number of free bytes.

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

const stats = await statfs('/');
const freeBytes = stats.bsize * stats.bfree;
console.log(`Free space: ${freeBytes} bytes`);
const { statfs } = require('node:fs/promises');

(async () => {
  const stats = await statfs('/');
  const freeBytes = stats.bsize * stats.bfree;
  console.log(`Free space: ${freeBytes} bytes`);
})();
javascript
statfs.blocks#

Total data blocks in file system. Multiply by statfs.bsize to get the total size in bytes.

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

const stats = await statfs('/');
const totalBytes = stats.bsize * stats.blocks;
console.log(`Total space: ${totalBytes} bytes`);
const { statfs } = require('node:fs/promises');

(async () => {
  const stats = await statfs('/');
  const totalBytes = stats.bsize * stats.blocks;
  console.log(`Total space: ${totalBytes} bytes`);
})();
javascript
statfs.bsize#

Optimal transfer block size in bytes.

statfs.frsize#

Fundamental file system block size.

statfs.ffree#

Free file nodes in file system.

statfs.files#

Total file nodes in file system.

statfs.type#

Type of file system. A platform-specific numeric identifier for the type of file system. This value corresponds to the f_type field returned by statfs(2) on POSIX systems (for example, 0xEF53 for ext4 on Linux). Its meaning is OS-dependent and is not guaranteed to be consistent across platforms.

Class: fs.Utf8Stream#

Stability: 1 - Experimental

An optimized UTF-8 stream writer that allows for flushing all the internal buffering on demand. It handles EAGAIN errors correctly, allowing for customization, for example, by dropping content if the disk is busy.

Event: 'close'#

The 'close' event is emitted when the stream is fully closed.

Event: 'drain'#

The 'drain' event is emitted when the internal buffer has drained sufficiently to allow continued writing.

Event: 'drop'#

The 'drop' event is emitted when the maximal length is reached and that data will not be written. The data that was dropped is passed as the first argument to the event handler.

Event: 'error'#

The 'error' event is emitted when an error occurs.

Event: 'finish'#

The 'finish' event is emitted when the stream has been ended and all data has been flushed to the underlying file.

Event: 'ready'#

The 'ready' event is emitted when the stream is ready to accept writes.

Event: 'write'#

The 'write' event is emitted when a write operation has completed. The number of bytes written is passed as the first argument to the event handler.

new fs.Utf8Stream([options])#
  • options <Object>
    • append: <boolean> Appends writes to dest file instead of truncating it. Default: true.
    • contentMode: <string> Which type of data you can send to the write function, supported values are 'utf8' or 'buffer'. Default: 'utf8'.
    • dest: <string> A path to a file to be written to (mode controlled by the append option).
    • fd: <number> A file descriptor, something that is returned by fs.open() or fs.openSync().
    • fs: <Object> An object that has the same API as the fs module, useful for mocking, testing, or customizing the behavior of the stream.
    • fsync: <boolean> Perform a fs.fsyncSync() every time a write is completed.
    • maxLength: <number> The maximum length of the internal buffer. If a write operation would cause the buffer to exceed maxLength, the data written is dropped and a drop event is emitted with the dropped data
    • maxWrite: <number> The maximum number of bytes that can be written; Default: 16384
    • minLength: <number> The minimum length of the internal buffer that is required to be full before flushing.
    • mkdir: <boolean> Ensure directory for dest file exists when true. Default: false.
    • mode: <number> | <string> Specify the creating file mode (see fs.open()).
    • periodicFlush: <number> Calls flush every periodicFlush milliseconds.
    • retryEAGAIN <Function> A function that will be called when write(), writeSync(), or flushSync() encounters an EAGAIN or EBUSY error. If the return value is true the operation will be retried, otherwise it will bubble the error. The err is the error that caused this function to be called, writeBufferLen is the length of the buffer that was written, and remainingBufferLen is the length of the remaining buffer that the stream did not try to write.
    • sync: <boolean> Perform writes synchronously.
utf8Stream.append#
  • <boolean> Whether the stream is appending to the file or truncating it.
utf8Stream.contentMode#
  • <string> The type of data that can be written to the stream. Supported values are 'utf8' or 'buffer'. Default: 'utf8'.
utf8Stream.destroy()#

Close the stream immediately, without flushing the internal buffer.

utf8Stream.end()#

Close the stream gracefully, flushing the internal buffer before closing.

utf8Stream.fd#
  • <number> The file descriptor that is being written to.
utf8Stream.file#
  • <string> The file that is being written to.
utf8Stream.flush(callback)#

Writes the current buffer to the file if a write was not in progress. Do nothing if minLength is zero or if it is already writing.

utf8Stream.flushSync()#

Flushes the buffered data synchronously. This is a costly operation.

utf8Stream.fsync#
  • <boolean> Whether the stream is performing a fs.fsyncSync() after every write operation.
utf8Stream.maxLength#
  • <number> The maximum length of the internal buffer. If a write operation would cause the buffer to exceed maxLength, the data written is dropped and a drop event is emitted with the dropped data.
utf8Stream.minLength#
  • <number> The minimum length of the internal buffer that is required to be full before flushing.
utf8Stream.mkdir#
  • <boolean> Whether the stream should ensure that the directory for the dest file exists. If true, it will create the directory if it does not exist. Default: false.
utf8Stream.mode#
utf8Stream.periodicFlush#
  • <number> The number of milliseconds between flushes. If set to 0, no periodic flushes will be performed.
utf8Stream.reopen(file)#
  • file: <string> | <Buffer> | <URL> A path to a file to be written to (mode controlled by the append option).

Reopen the file in place, useful for log rotation.

utf8Stream.sync#
  • <boolean> Whether the stream is writing synchronously or asynchronously.
utf8Stream.write(data)#

When the options.contentMode is set to 'utf8' when the stream is created, the data argument must be a string. If the contentMode is set to 'buffer', the data argument must be a <Buffer>.

utf8Stream.writing#
  • <boolean> Whether the stream is currently writing data to the file.
utf8Stream[Symbol.dispose]()#

Calls utf8Stream.destroy().

Class: fs.WriteStream#

Instances of <fs.WriteStream> cannot be constructed directly. They are created and returned using the fs.createWriteStream() function.

Event: 'close'#

Emitted when the <fs.WriteStream>'s underlying file descriptor has been closed.

Event: 'open'#

Emitted when the <fs.WriteStream>'s file is opened.

Event: 'ready'#

Emitted when the <fs.WriteStream> is ready to be used.

Fires immediately after 'open'.

writeStream.bytesWritten#

The number of bytes written so far. Does not include data that is still queued for writing.

writeStream.close([callback])#

Closes writeStream. Optionally accepts a callback that will be executed once the writeStream is closed.

writeStream.path#

The path to the file the stream is writing to as specified in the first argument to fs.createWriteStream(). If path is passed as a string, then writeStream.path will be a string. If path is passed as a <Buffer>, then writeStream.path will be a <Buffer>.

writeStream.pending#

This property is true if the underlying file has not been opened yet, i.e. before the 'ready' event is emitted.

fs.constants#

Returns an object containing commonly used constants for file system operations.

FS constants#

The following constants are exported by fs.constants and fsPromises.constants.

Not every constant will be available on every operating system; this is especially important for Windows, where many of the POSIX specific definitions are not available. For portable applications it is recommended to check for their presence before use.

To use more than one constant, use the bitwise OR | operator.

Example:

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

const {
  O_RDWR,
  O_CREAT,
  O_EXCL,
} = constants;

open('/path/to/my/file', O_RDWR | O_CREAT | O_EXCL, (err, fd) => {
  // ...
});
mjs
File access constants#

The following constants are meant for use as the mode parameter passed to fsPromises.access(), fs.access(), and fs.accessSync().

Constant Description
F_OK Flag indicating that the file is visible to the calling process. This is useful for determining if a file exists, but says nothing about rwx permissions. Default if no mode is specified.
R_OK Flag indicating that the file can be read by the calling process.
W_OK Flag indicating that the file can be written by the calling process.
X_OK Flag indicating that the file can be executed by the calling process. This has no effect on Windows (will behave like fs.constants.F_OK).

The definitions are also available on Windows.

File copy constants#

The following constants are meant for use with fs.copyFile().

Constant Description
COPYFILE_EXCL If present, the copy operation will fail with an error if the destination path already exists.
COPYFILE_FICLONE If present, the copy operation will attempt to create a copy-on-write reflink. If the underlying platform does not support copy-on-write, then a fallback copy mechanism is used.
COPYFILE_FICLONE_FORCE If present, the copy operation will attempt to create a copy-on-write reflink. If the underlying platform does not support copy-on-write, then the operation will fail with an error.

The definitions are also available on Windows.

File open constants#

The following constants are meant for use with fs.open().

Constant Description
O_RDONLY Flag indicating to open a file for read-only access.
O_WRONLY Flag indicating to open a file for write-only access.
O_RDWR Flag indicating to open a file for read-write access.
O_CREAT Flag indicating to create the file if it does not already exist.
O_EXCL Flag indicating that opening a file should fail if the O_CREAT flag is set and the file already exists.
O_NOCTTY Flag indicating that if path identifies a terminal device, opening the path shall not cause that terminal to become the controlling terminal for the process (if the process does not already have one).
O_TRUNC Flag indicating that if the file exists and is a regular file, and the file is opened successfully for write access, its length shall be truncated to zero.
O_APPEND Flag indicating that data will be appended to the end of the file.
O_DIRECTORY Flag indicating that the open should fail if the path is not a directory.
O_NOATIME Flag indicating reading accesses to the file system will no longer result in an update to the atime information associated with the file. This flag is available on Linux operating systems only.
O_NOFOLLOW Flag indicating that the open should fail if the path is a symbolic link.
O_SYNC Flag indicating that the file is opened for synchronized I/O with write operations waiting for file integrity.
O_DSYNC Flag indicating that the file is opened for synchronized I/O with write operations waiting for data integrity.
O_SYMLINK Flag indicating to open the symbolic link itself rather than the resource it is pointing to.
O_DIRECT When set, an attempt will be made to minimize caching effects of file I/O.
O_NONBLOCK Flag indicating to open the file in nonblocking mode when possible.
UV_FS_O_FILEMAP When set, a memory file mapping is used to access the file. This flag is available on Windows operating systems only. On other operating systems, this flag is ignored.

On Windows, only O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, and UV_FS_O_FILEMAP are available.

File type constants#

The following constants are meant for use with the <fs.Stats> object's mode property for determining a file's type.

Constant Description
S_IFMT Bit mask used to extract the file type code.
S_IFREG File type constant for a regular file.
S_IFDIR File type constant for a directory.
S_IFCHR File type constant for a character-oriented device file.
S_IFBLK File type constant for a block-oriented device file.
S_IFIFO File type constant for a FIFO/pipe.
S_IFLNK File type constant for a symbolic link.
S_IFSOCK File type constant for a socket.

On Windows, only S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, and S_IFREG, are available.

File mode constants#

The following constants are meant for use with the <fs.Stats> object's mode property for determining the access permissions for a file.

Constant Description
S_IRWXU File mode indicating readable, writable, and executable by owner.
S_IRUSR File mode indicating readable by owner.
S_IWUSR File mode indicating writable by owner.
S_IXUSR File mode indicating executable by owner.
S_IRWXG File mode indicating readable, writable, and executable by group.
S_IRGRP File mode indicating readable by group.
S_IWGRP File mode indicating writable by group.
S_IXGRP File mode indicating executable by group.
S_IRWXO File mode indicating readable, writable, and executable by others.
S_IROTH File mode indicating readable by others.
S_IWOTH File mode indicating writable by others.
S_IXOTH File mode indicating executable by others.

On Windows, only S_IRUSR and S_IWUSR are available.

Notes#

Ordering of callback and promise-based operations#

Because they are executed asynchronously by the underlying thread pool, there is no guaranteed ordering when using either the callback or promise-based methods.

For example, the following is prone to error because the fs.stat() operation might complete before the fs.rename() operation:

const fs = require('node:fs');

fs.rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  console.log('renamed complete');
});
fs.stat('/tmp/world', (err, stats) => {
  if (err) throw err;
  console.log(`stats: ${JSON.stringify(stats)}`);
});
js

It is important to correctly order the operations by awaiting the results of one before invoking the other:

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

const oldPath = '/tmp/hello';
const newPath = '/tmp/world';

try {
  await rename(oldPath, newPath);
  const stats = await stat(newPath);
  console.log(`stats: ${JSON.stringify(stats)}`);
} catch (error) {
  console.error('there was an error:', error.message);
}
const { rename, stat } = require('node:fs/promises');

(async function(oldPath, newPath) {
  try {
    await rename(oldPath, newPath);
    const stats = await stat(newPath);
    console.log(`stats: ${JSON.stringify(stats)}`);
  } catch (error) {
    console.error('there was an error:', error.message);
  }
})('/tmp/hello', '/tmp/world');
javascript

Or, when using the callback APIs, move the fs.stat() call into the callback of the fs.rename() operation:

import { rename, stat } from 'node:fs';

rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  stat('/tmp/world', (err, stats) => {
    if (err) throw err;
    console.log(`stats: ${JSON.stringify(stats)}`);
  });
});
const { rename, stat } = require('node:fs');

rename('/tmp/hello', '/tmp/world', (err) => {
  if (err) throw err;
  stat('/tmp/world', (err, stats) => {
    if (err) throw err;
    console.log(`stats: ${JSON.stringify(stats)}`);
  });
});
javascript

File paths#

Most fs operations accept file paths that may be specified in the form of a string, a <Buffer>, or a <URL> object using the file: protocol.

String paths#

String paths are interpreted as UTF-8 character sequences identifying the absolute or relative filename. Relative paths will be resolved relative to the current working directory as determined by calling process.cwd().

Example using an absolute path on POSIX:

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

let fd;
try {
  fd = await open('/open/some/file.txt', 'r');
  // Do something with the file
} finally {
  await fd?.close();
}
mjs

Example using a relative path on POSIX (relative to process.cwd()):

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

let fd;
try {
  fd = await open('file.txt', 'r');
  // Do something with the file
} finally {
  await fd?.close();
}
mjs
File URL paths#

For most node:fs module functions, the path or filename argument may be passed as a <URL> object using the file: protocol.

import { readFileSync } from 'node:fs';

readFileSync(new URL('file:///tmp/hello'));
mjs

file: URLs are always absolute paths.

Platform-specific considerations#

On Windows, file: <URL>s with a host name convert to UNC paths, while file: <URL>s with drive letters convert to local absolute paths. file: <URL>s with no host name and no drive letter will result in an error:

import { readFileSync } from 'node:fs';
// On Windows :

// - WHATWG file URLs with hostname convert to UNC path
// file://hostname/p/a/t/h/file => \\hostname\p\a\t\h\file
readFileSync(new URL('file://hostname/p/a/t/h/file'));

// - WHATWG file URLs with drive letters convert to absolute path
// file:///C:/tmp/hello => C:\tmp\hello
readFileSync(new URL('file:///C:/tmp/hello'));

// - WHATWG file URLs without hostname must have a drive letters
readFileSync(new URL('file:///notdriveletter/p/a/t/h/file'));
readFileSync(new URL('file:///c/p/a/t/h/file'));
// TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must be absolute
mjs

file: <URL>s with drive letters must use : as a separator just after the drive letter. Using another separator will result in an error.

On all other platforms, file: <URL>s with a host name are unsupported and will result in an error:

import { readFileSync } from 'node:fs';
// On other platforms:

// - WHATWG file URLs with hostname are unsupported
// file://hostname/p/a/t/h/file => throw!
readFileSync(new URL('file://hostname/p/a/t/h/file'));
// TypeError [ERR_INVALID_FILE_URL_PATH]: must be absolute

// - WHATWG file URLs convert to absolute path
// file:///tmp/hello => /tmp/hello
readFileSync(new URL('file:///tmp/hello'));
mjs

A file: <URL> having encoded slash characters will result in an error on all platforms:

import { readFileSync } from 'node:fs';

// On Windows
readFileSync(new URL('file:///C:/p/a/t/h/%2F'));
readFileSync(new URL('file:///C:/p/a/t/h/%2f'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
\ or / characters */

// On POSIX
readFileSync(new URL('file:///p/a/t/h/%2F'));
readFileSync(new URL('file:///p/a/t/h/%2f'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
/ characters */
mjs

On Windows, file: <URL>s having encoded backslash will result in an error:

import { readFileSync } from 'node:fs';

// On Windows
readFileSync(new URL('file:///C:/path/%5C'));
readFileSync(new URL('file:///C:/path/%5c'));
/* TypeError [ERR_INVALID_FILE_URL_PATH]: File URL path must not include encoded
\ or / characters */
mjs
Buffer paths#

Paths specified using a <Buffer> are useful primarily on certain POSIX operating systems that treat file paths as opaque byte sequences. On such systems, it is possible for a single file path to contain sub-sequences that use multiple character encodings. As with string paths, <Buffer> paths may be relative or absolute:

Example using an absolute path on POSIX:

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

let fd;
try {
  fd = await open(Buffer.from('/open/some/file.txt'), 'r');
  // Do something with the file
} finally {
  await fd?.close();
}
mjs
Per-drive working directories on Windows#

On Windows, Node.js follows the concept of per-drive working directory. This behavior can be observed when using a drive path without a backslash. For example fs.readdirSync('C:\\') can potentially return a different result than fs.readdirSync('C:'). For more information, see this MSDN page.

File descriptors#

On POSIX systems, for every process, the kernel maintains a table of currently open files and resources. Each open file is assigned a simple numeric identifier called a file descriptor. At the system-level, all file system operations use these file descriptors to identify and track each specific file. Windows systems use a different but conceptually similar mechanism for tracking resources. To simplify things for users, Node.js abstracts away the differences between operating systems and assigns all open files a numeric file descriptor.

The callback-based fs.open(), and synchronous fs.openSync() methods open a file and allocate a new file descriptor. Once allocated, the file descriptor may be used to read data from, write data to, or request information about the file.

Operating systems limit the number of file descriptors that may be open at any given time so it is critical to close the descriptor when operations are completed. Failure to do so will result in a memory leak that will eventually cause an application to crash.

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

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

open('/open/some/file.txt', 'r', (err, fd) => {
  if (err) throw err;
  try {
    fstat(fd, (err, stat) => {
      if (err) {
        closeFd(fd);
        throw err;
      }

      // use stat

      closeFd(fd);
    });
  } catch (err) {
    closeFd(fd);
    throw err;
  }
});
mjs

The promise-based APIs use a <FileHandle> object in place of the numeric file descriptor. These objects are better managed by the system to ensure that resources are not leaked. However, it is still required that they are closed when operations are completed:

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

let file;
try {
  file = await open('/open/some/file.txt', 'r');
  const stat = await file.stat();
  // use stat
} finally {
  await file.close();
}
mjs

Threadpool usage#

All callback and promise-based file system APIs (with the exception of fs.FSWatcher()) use libuv's threadpool. This can have surprising and negative performance implications for some applications. See the UV_THREADPOOL_SIZE documentation for more information.

File system flags#

The following flags are available wherever the flag option takes a string.

  • 'a': Open file for appending. The file is created if it does not exist.

  • 'ax': Like 'a' but fails if the path exists.

  • 'a+': Open file for reading and appending. The file is created if it does not exist.

  • 'ax+': Like 'a+' but fails if the path exists.

  • 'as': Open file for appending in synchronous mode. The file is created if it does not exist.

  • 'as+': Open file for reading and appending in synchronous mode. The file is created if it does not exist.

  • 'r': Open file for reading. An exception occurs if the file does not exist.

  • 'rs': Open file for reading in synchronous mode. An exception occurs if the file does not exist.

  • 'r+': Open file for reading and writing. An exception occurs if the file does not exist.

  • 'rs+': Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.

    This is primarily useful for opening files on NFS mounts as it allows skipping the potentially stale local cache. It has a very real impact on I/O performance so using this flag is not recommended unless it is needed.

    This doesn't turn fs.open() or fsPromises.open() into a synchronous blocking call. If synchronous operation is desired, something like fs.openSync() should be used.

  • 'w': Open file for writing. The file is created (if it does not exist) or truncated (if it exists).

  • 'wx': Like 'w' but fails if the path exists.

  • 'w+': Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).

  • 'wx+': Like 'w+' but fails if the path exists.

flag can also be a number as documented by open(2); commonly used constants are available from fs.constants. On Windows, flags are translated to their equivalent ones where applicable, e.g. O_WRONLY to FILE_GENERIC_WRITE, or O_EXCL|O_CREAT to CREATE_NEW, as accepted by CreateFileW.

The exclusive flag 'x' (O_EXCL flag in open(2)) causes the operation to return an error if the path already exists. On POSIX, if the path is a symbolic link, using O_EXCL returns an error even if the link is to a path that does not exist. The exclusive flag might not work with network file systems.

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.

Modifying a file rather than replacing it may require the flag option to be set to 'r+' rather than the default 'w'.

The behavior of some flags are platform-specific. As such, opening a directory on macOS and Linux with the 'a+' flag, as in the example below, will return an error. In contrast, on Windows and FreeBSD, a file descriptor or a FileHandle will be returned.

// macOS and Linux
fs.open('<directory>', 'a+', (err, fd) => {
  // => [Error: EISDIR: illegal operation on a directory, open <directory>]
});

// Windows and FreeBSD
fs.open('<directory>', 'a+', (err, fd) => {
  // => null, <fd>
});
js

On Windows, opening an existing hidden file using the 'w' flag (either through fs.open(), fs.writeFile(), or fsPromises.open()) will fail with EPERM. Existing hidden files can be opened for writing with the 'r+' flag.

A call to fs.ftruncate() or filehandle.truncate() can be used to reset the file contents.

Global objects#

Stability: 2 - Stable

These objects are available in all modules.

The following variables may appear to be global but are not. They exist only in the scope of CommonJS modules:

The objects listed here are specific to Node.js. There are built-in objects that are part of the JavaScript language itself, which are also globally accessible.

__dirname#

This variable may appear to be global but is not. See __dirname.

__filename#

This variable may appear to be global but is not. See __filename.

Class: AbortController#

A utility class used to signal cancelation in selected Promise-based APIs. The API is based on the Web API <AbortController>.

const ac = new AbortController();

ac.signal.addEventListener('abort', () => console.log('Aborted!'),
                           { once: true });

ac.abort();

console.log(ac.signal.aborted);  // Prints true
js

abortController.abort([reason])#

  • reason <any> An optional reason, retrievable on the AbortSignal's reason property.

Triggers the abort signal, causing the abortController.signal to emit the 'abort' event.

abortController.signal#

Class: AbortSignal#

The AbortSignal is used to notify observers when the abortController.abort() method is called.

Static method: AbortSignal.abort([reason])#

Returns a new already aborted AbortSignal.

Static method: AbortSignal.timeout(delay)#

  • delay <number> The number of milliseconds to wait before triggering the AbortSignal.

Returns a new AbortSignal which will be aborted in delay milliseconds.

Static method: AbortSignal.any(signals)#

  • signals <AbortSignal>[] The AbortSignals of which to compose a new AbortSignal.

Returns a new AbortSignal which will be aborted if any of the provided signals are aborted. Its abortSignal.reason will be set to whichever one of the signals caused it to be aborted.

Event: 'abort'#

The 'abort' event is emitted when the abortController.abort() method is called. The callback is invoked with a single object argument with a single type property set to 'abort':

const ac = new AbortController();

// Use either the onabort property...
ac.signal.onabort = () => console.log('aborted!');

// Or the EventTarget API...
ac.signal.addEventListener('abort', (event) => {
  console.log(event.type);  // Prints 'abort'
}, { once: true });

ac.abort();
js

The AbortController with which the AbortSignal is associated will only ever trigger the 'abort' event once. We recommended that code check that the abortSignal.aborted attribute is false before adding an 'abort' event listener.

Any event listeners attached to the AbortSignal should use the { once: true } option (or, if using the EventEmitter APIs to attach a listener, use the once() method) to ensure that the event listener is removed as soon as the 'abort' event is handled. Failure to do so may result in memory leaks.

abortSignal.aborted#

True after the AbortController has been aborted.

abortSignal.onabort#

An optional callback function that may be set by user code to be notified when the abortController.abort() function has been called.

abortSignal.reason#

An optional reason specified when the AbortSignal was triggered.

const ac = new AbortController();
ac.abort(new Error('boom!'));
console.log(ac.signal.reason);  // Error: boom!
js

abortSignal.throwIfAborted()#

If abortSignal.aborted is true, throws abortSignal.reason.

atob(data)#

Stability: 3 - Legacy. Use Buffer.from(data, 'base64') instead.

Global alias for buffer.atob().

An automated migration is available (source):

npx codemod@latest @nodejs/buffer-atob-btoa
bash

Class: Blob#

See <Blob>.

Class: BroadcastChannel#

See <BroadcastChannel>.

btoa(data)#

Stability: 3 - Legacy. Use buf.toString('base64') instead.

Global alias for buffer.btoa().

An automated migration is available (source):

npx codemod@latest @nodejs/buffer-atob-btoa
bash

Class: Buffer#

Used to handle binary data. See the buffer section.

Class: ByteLengthQueuingStrategy#

A browser-compatible implementation of ByteLengthQueuingStrategy.

clearImmediate(immediateObject)#

clearImmediate is described in the timers section.

clearInterval(intervalObject)#

clearInterval is described in the timers section.

clearTimeout(timeoutObject)#

clearTimeout is described in the timers section.

Class: CloseEvent#

A browser-compatible implementation of <CloseEvent>. Disable this API with the --no-experimental-websocket CLI flag.

Class: CompressionStream#

A browser-compatible implementation of CompressionStream.

console#

Used to print to stdout and stderr. See the console section.

Class: CountQueuingStrategy#

A browser-compatible implementation of CountQueuingStrategy.

Class: Crypto#

A browser-compatible implementation of <Crypto>. This global is available only if the Node.js binary was compiled with including support for the node:crypto module.

crypto#

A browser-compatible implementation of the Web Crypto API.

Class: CryptoKey#

A browser-compatible implementation of <CryptoKey>. This global is available only if the Node.js binary was compiled with including support for the node:crypto module.

Class: CustomEvent#

A browser-compatible implementation of <CustomEvent>.

Class: DecompressionStream#

A browser-compatible implementation of DecompressionStream.

Class: DOMException#

The WHATWG <DOMException> class.

ErrorEvent#

A browser-compatible implementation of <ErrorEvent>.

Class: Event#

A browser-compatible implementation of the Event class. See EventTarget and Event API for more details.

Class: EventSource#

Stability: 1 - Experimental. Enable this API with the --experimental-eventsource CLI flag.

A browser-compatible implementation of <EventSource>.

Class: EventTarget#

A browser-compatible implementation of the EventTarget class. See EventTarget and Event API for more details.

exports#

This variable may appear to be global but is not. See exports.

fetch#

A browser-compatible implementation of the fetch() function.

const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
  const data = await res.json();
  console.log(data);
}
mjs

The implementation is based upon undici, an HTTP/1.1 client written from scratch for Node.js. You can figure out which version of undici is bundled in your Node.js process reading the process.versions.undici property.

Custom dispatcher#

You can use a custom dispatcher to dispatch requests passing it in fetch's options object. The dispatcher must be compatible with undici's Dispatcher class.

fetch(url, { dispatcher: new MyAgent() });
js

It is possible to change the global dispatcher in Node.js by installing undici and using the setGlobalDispatcher() method. Calling this method will affect both undici and Node.js.

import { setGlobalDispatcher } from 'undici';
setGlobalDispatcher(new MyAgent());
mjs

Related classes#

The following globals are available to use with fetch:

Class: File#

See <File>.

Class: FormData#

A browser-compatible implementation of <FormData>.

global#

Stability: 3 - Legacy. Use globalThis instead.

  • Type: <Object> The global namespace object.

In browsers, the top-level scope has traditionally been the global scope. This means that var something will define a new global variable, except within ECMAScript modules. In Node.js, this is different. The top-level scope is not the global scope; var something inside a Node.js module will be local to that module, regardless of whether it is a CommonJS module or an ECMAScript module.

Class: Headers#

A browser-compatible implementation of <Headers>.

localStorage#

Stability: 1.2 - Release candidate. Disable this API with --no-experimental-webstorage.

A browser-compatible implementation of localStorage. Data is stored unencrypted in the file specified by the --localstorage-file CLI flag. The maximum amount of data that can be stored is 10 MB. Any modification of this data outside of the Web Storage API is not supported. localStorage data is not stored per user or per request when used in the context of a server, it is shared across all users and requests.

Class: MessageChannel#

The MessageChannel class. See MessageChannel for more details.

Class: MessageEvent#

A browser-compatible implementation of <MessageEvent>.

Class: MessagePort#

The MessagePort class. See MessagePort for more details.

module#

This variable may appear to be global but is not. See module.

Class: Navigator#

Stability: 1.1 - Active development. Disable this API with the --no-experimental-global-navigator CLI flag.

A partial implementation of the Navigator API.

navigator#

Stability: 1.1 - Active development. Disable this API with the --no-experimental-global-navigator CLI flag.

A partial implementation of window.navigator.

navigator.hardwareConcurrency#

The navigator.hardwareConcurrency read-only property returns the number of logical processors available to the current Node.js instance.

console.log(`This process is running on ${navigator.hardwareConcurrency} logical processors`);
js

navigator.language#

The navigator.language read-only property returns a string representing the preferred language of the Node.js instance. The language will be determined by the ICU library used by Node.js at runtime based on the default language of the operating system.

The value is representing the language version as defined in RFC 5646.

The fallback value on builds without ICU is 'en-US'.

console.log(`The preferred language of the Node.js instance has the tag '${navigator.language}'`);
js

navigator.languages#

The navigator.languages read-only property returns an array of strings representing the preferred languages of the Node.js instance. By default navigator.languages contains only the value of navigator.language, which will be determined by the ICU library used by Node.js at runtime based on the default language of the operating system.

The fallback value on builds without ICU is ['en-US'].

console.log(`The preferred languages are '${navigator.languages}'`);
js

navigator.locks#

Stability: 1 - Experimental

The navigator.locks read-only property returns a LockManager instance that can be used to coordinate access to resources that may be shared across multiple threads within the same process. This global implementation matches the semantics of the browser LockManager API.

// Request an exclusive lock
await navigator.locks.request('my_resource', async (lock) => {
  // The lock has been acquired.
  console.log(`Lock acquired: ${lock.name}`);
  // Lock is automatically released when the function returns
});

// Request a shared lock
await navigator.locks.request('shared_resource', { mode: 'shared' }, async (lock) => {
  // Multiple shared locks can be held simultaneously
  console.log(`Shared lock acquired: ${lock.name}`);
});
// Request an exclusive lock
navigator.locks.request('my_resource', async (lock) => {
  // The lock has been acquired.
  console.log(`Lock acquired: ${lock.name}`);
  // Lock is automatically released when the function returns
}).then(() => {
  console.log('Lock released');
});

// Request a shared lock
navigator.locks.request('shared_resource', { mode: 'shared' }, async (lock) => {
  // Multiple shared locks can be held simultaneously
  console.log(`Shared lock acquired: ${lock.name}`);
}).then(() => {
  console.log('Shared lock released');
});
javascript

See worker_threads.locks for detailed API documentation.

navigator.platform#

The navigator.platform read-only property returns a string identifying the platform on which the Node.js instance is running.

console.log(`This process is running on ${navigator.platform}`);
js

navigator.userAgent#

The navigator.userAgent read-only property returns user agent consisting of the runtime name and major version number.

console.log(`The user-agent is ${navigator.userAgent}`); // Prints "Node.js/21"
js

performance#

The perf_hooks.performance object.

Class: PerformanceEntry#

The PerformanceEntry class. See PerformanceEntry for more details.

Class: PerformanceMark#

The PerformanceMark class. See PerformanceMark for more details.

Class: PerformanceMeasure#

The PerformanceMeasure class. See PerformanceMeasure for more details.

Class: PerformanceObserver#

The PerformanceObserver class. See PerformanceObserver for more details.

Class: PerformanceObserverEntryList#

The PerformanceObserverEntryList class. See PerformanceObserverEntryList for more details.

Class: PerformanceResourceTiming#

The PerformanceResourceTiming class. See PerformanceResourceTiming for more details.

process#

The process object. See the process object section.

queueMicrotask(callback)#

The queueMicrotask() method queues a microtask to invoke callback. If callback throws an exception, the process object 'uncaughtException' event will be emitted.

The microtask queue is managed by V8 and may be used in a similar manner to the process.nextTick() queue, which is managed by Node.js. The process.nextTick() queue is always processed before the microtask queue within each turn of the Node.js event loop.

// Here, `queueMicrotask()` is used to ensure the 'load' event is always
// emitted asynchronously, and therefore consistently. Using
// `process.nextTick()` here would result in the 'load' event always emitting
// before any other promise jobs.

DataHandler.prototype.load = async function load(key) {
  const hit = this._cache.get(key);
  if (hit !== undefined) {
    queueMicrotask(() => {
      this.emit('load', hit);
    });
    return;
  }

  const data = await fetchData(key);
  this._cache.set(key, data);
  this.emit('load', data);
};
js

Class: QuotaExceededError#

The WHATWG <QuotaExceededError> class. Extends <DOMException>.

Class: ReadableByteStreamController#

A browser-compatible implementation of ReadableByteStreamController.

Class: ReadableStream#

A browser-compatible implementation of ReadableStream.

Class: ReadableStreamBYOBReader#

A browser-compatible implementation of ReadableStreamBYOBReader.

Class: ReadableStreamBYOBRequest#

A browser-compatible implementation of ReadableStreamBYOBRequest.

Class: ReadableStreamDefaultController#

A browser-compatible implementation of ReadableStreamDefaultController.

Class: ReadableStreamDefaultReader#

A browser-compatible implementation of ReadableStreamDefaultReader.

Class: Request#

A browser-compatible implementation of <Request>.

require()#

This variable may appear to be global but is not. See require().

Class: Response#

A browser-compatible implementation of <Response>.

sessionStorage#

Stability: 1.2 - Release candidate. Disable this API with --no-experimental-webstorage.

A browser-compatible implementation of sessionStorage. Data is stored in memory, with a storage quota of 10 MB. sessionStorage data persists only within the currently running process, and is not shared between workers.

setImmediate(callback[, ...args])#

setImmediate is described in the timers section.

setInterval(callback, delay[, ...args])#

setInterval is described in the timers section.

setTimeout(callback, delay[, ...args])#

setTimeout is described in the timers section.

Class: Storage#

Stability: 1.2 - Release candidate. Disable this API with --no-experimental-webstorage.

A browser-compatible implementation of <Storage>.

structuredClone(value[, options])#

The WHATWG structuredClone method.

Class: SubtleCrypto#

A browser-compatible implementation of <SubtleCrypto>. This global is available only if the Node.js binary was compiled with including support for the node:crypto module.

Class: TextDecoder#

The WHATWG TextDecoder class. See the TextDecoder section.

Class: TextDecoderStream#

A browser-compatible implementation of TextDecoderStream.

Class: TextEncoder#

The WHATWG TextEncoder class. See the TextEncoder section.

Class: TextEncoderStream#

A browser-compatible implementation of TextEncoderStream.

Class: TransformStream#

A browser-compatible implementation of TransformStream.

Class: TransformStreamDefaultController#

A browser-compatible implementation of TransformStreamDefaultController.

Class: URL#

The WHATWG URL class. See the URL section.

Class: URLPattern#

Stability: 1 - Experimental

The WHATWG URLPattern class. See the URLPattern section.

Class: URLSearchParams#

The WHATWG URLSearchParams class. See the URLSearchParams section.

Class: WebAssembly#

The object that acts as the namespace for all W3C WebAssembly related functionality. See the Mozilla Developer Network for usage and compatibility.

Class: WebSocket#

A browser-compatible implementation of <WebSocket>. Disable this API with the --no-experimental-websocket CLI flag.

Class: WritableStream#

A browser-compatible implementation of WritableStream.

Class: WritableStreamDefaultController#

A browser-compatible implementation of WritableStreamDefaultController.

Class: WritableStreamDefaultWriter#

A browser-compatible implementation of WritableStreamDefaultWriter.

HTTP#

Stability: 2 - Stable

This module, containing both a client and server, can be imported via require('node:http') (CommonJS) or import * as http from 'node:http' (ES module).

The HTTP interfaces in Node.js are designed to support many features of the protocol which have been traditionally difficult to use. In particular, large, possibly chunk-encoded, messages. The interface is careful to never buffer entire requests or responses, so the user is able to stream data.

HTTP message headers are represented by an object like this:

{ "content-length": "123",
  "content-type": "text/plain",
  "connection": "keep-alive",
  "host": "example.com",
  "accept": "*/*" }
json

Keys are lowercased. Values are not modified.

In order to support the full spectrum of possible HTTP applications, the Node.js HTTP API is very low-level. It deals with stream handling and message parsing only. It parses a message into headers and body but it does not parse the actual headers or the body.

See message.headers for details on how duplicate headers are handled.

The raw headers as they were received are retained in the rawHeaders property, which is an array of [key, value, key2, value2, ...]. For example, the previous message header object might have a rawHeaders list like the following:

[ "ConTent-Length", "123456",
  "content-LENGTH", "123",
  "content-type", "text/plain",
  "CONNECTION", "keep-alive",
  "Host", "example.com",
  "accepT", "*/*" ]
json

Class: http.Agent#

An Agent is responsible for managing connection persistence and reuse for HTTP clients. It maintains a queue of pending requests for a given host and port, reusing a single socket connection for each until the queue is empty, at which time the socket is either destroyed or put into a pool where it is kept to be used again for requests to the same host and port. Whether it is destroyed or pooled depends on the keepAlive option.

Pooled connections have TCP Keep-Alive enabled for them, but servers may still close idle connections, in which case they will be removed from the pool and a new connection will be made when a new HTTP request is made for that host and port. Servers may also refuse to allow multiple requests over the same connection, in which case the connection will have to be remade for every request and cannot be pooled. The Agent will still make the requests to that server, but each one will occur over a new connection.

Response ordering with connection reuse#

On a reused HTTP/1.1 keep-alive connection, responses are associated with requests by their order on that connection. HTTP/1.1 keep-alive does not provide per-request response attribution beyond that ordering. Applications that require per-request connection isolation can use a separate Agent, disable keep-alive, or pass agent: false.

When a connection is closed by the client or the server, it is removed from the pool. Any unused sockets in the pool will be unrefed so as not to keep the Node.js process running when there are no outstanding requests. (see socket.unref()).

It is good practice, to destroy() an Agent instance when it is no longer in use, because unused sockets consume OS resources.

Sockets are removed from an agent when the socket emits either a 'close' event or an 'agentRemove' event. When intending to keep one HTTP request open for a long time without keeping it in the agent, something like the following may be done:

http.get(options, (res) => {
  // Do stuff
}).on('socket', (socket) => {
  socket.emit('agentRemove');
});
js

An agent may also be used for an individual request. By providing {agent: false} as an option to the http.get() or http.request() functions, a one-time use Agent with default options will be used for the client connection.

agent:false:

http.get({
  hostname: 'localhost',
  port: 80,
  path: '/',
  agent: false,  // Create a new agent just for this one request
}, (res) => {
  // Do stuff with response
});
js

Use agent: false to avoid connection reuse for a request.

new Agent([options])#

  • options <Object> Set of configurable options to set on the agent. Can have the following fields:
    • keepAlive <boolean> Keep sockets around even when there are no outstanding requests, so they can be used for future requests without having to reestablish a TCP connection. Not to be confused with the keep-alive value of the Connection header. The Connection: keep-alive header is always sent when using an agent except when the Connection header is explicitly specified or when the keepAlive and maxSockets options are respectively set to false and Infinity, in which case Connection: close will be used. Default: false.
    • keepAliveMsecs <number> When using the keepAlive option, specifies the initial delay for TCP Keep-Alive packets. Ignored when the keepAlive option is false or undefined. Default: 1000.
    • agentKeepAliveTimeoutBuffer <number> Milliseconds to subtract from the server-provided keep-alive: timeout=... hint when determining socket expiration time. This buffer helps ensure the agent closes the socket slightly before the server does, reducing the chance of sending a request on a socket that’s about to be closed by the server. Default: 1000.
    • maxSockets <number> Maximum number of sockets to allow per host. If the same host opens multiple concurrent connections, each request will use new socket until the maxSockets value is reached. If the host attempts to open more connections than maxSockets, the additional requests will enter into a pending request queue, and will enter active connection state when an existing connection terminates. This makes sure there are at most maxSockets active connections at any point in time, from a given host. Default: Infinity.
    • maxTotalSockets <number> Maximum number of sockets allowed for all hosts in total. Each request will use a new socket until the maximum is reached. Default: Infinity.
    • maxFreeSockets <number> Maximum number of sockets per host to leave open in a free state. Only relevant if keepAlive is set to true. Default: 256.
    • scheduling <string> Scheduling strategy to apply when picking the next free socket to use. It can be 'fifo' or 'lifo'. The main difference between the two scheduling strategies is that 'lifo' selects the most recently used socket, while 'fifo' selects the least recently used socket. In case of a low rate of request per second, the 'lifo' scheduling will lower the risk of picking a socket that might have been closed by the server due to inactivity. In case of a high rate of request per second, the 'fifo' scheduling will maximize the number of open sockets, while the 'lifo' scheduling will keep it as low as possible. Default: 'lifo'.
    • timeout <number> Socket timeout in milliseconds. This will set the timeout when the socket is created.
    • proxyEnv <Object> | <undefined> Environment variables for proxy configuration. See Built-in Proxy Support for details. Default: undefined
      • HTTP_PROXY <string> | <undefined> URL for the proxy server that HTTP requests should use. If undefined, no proxy is used for HTTP requests.
      • HTTPS_PROXY <string> | <undefined> URL for the proxy server that HTTPS requests should use. If undefined, no proxy is used for HTTPS requests.
      • NO_PROXY <string> | <undefined> Patterns specifying the endpoints that should not be routed through a proxy.
      • http_proxy <string> | <undefined> Same as HTTP_PROXY. If both are set, http_proxy takes precedence.
      • https_proxy <string> | <undefined> Same as HTTPS_PROXY. If both are set, https_proxy takes precedence.
      • no_proxy <string> | <undefined> Same as NO_PROXY. If both are set, no_proxy takes precedence.
    • defaultPort <number> Default port to use when the port is not specified in requests. Default: 80.
    • protocol <string> The protocol to use for the agent. Default: 'http:'.

options in socket.connect() are also supported.

To configure any of them, a custom http.Agent instance must be created.

import { Agent, request } from 'node:http';
const keepAliveAgent = new Agent({ keepAlive: true });
options.agent = keepAliveAgent;
request(options, onResponseCallback);
const http = require('node:http');
const keepAliveAgent = new http.Agent({ keepAlive: true });
options.agent = keepAliveAgent;
http.request(options, onResponseCallback);
javascript

agent.createConnection(options[, callback])#

  • options <Object> Options containing connection details. Check net.createConnection() for the format of the options. For custom agents, this object is passed to the custom createConnection function.
  • callback <Function> (Optional, primarily for custom agents) A function to be called by a custom createConnection implementation when the socket is created, especially for asynchronous operations.
  • Returns: <stream.Duplex> The created socket. This is returned by the default implementation or by a custom synchronous createConnection implementation. If a custom createConnection uses the callback for asynchronous operation, this return value might not be the primary way to obtain the socket.

Produces a socket/stream to be used for HTTP requests.

By default, this function behaves identically to net.createConnection(), synchronously returning the created socket. The optional callback parameter in the signature is not used by this default implementation.

However, custom agents may override this method to provide greater flexibility, for example, to create sockets asynchronously. When overriding createConnection:

  1. Synchronous socket creation: The overriding method can return the socket/stream directly.
  2. Asynchronous socket creation: The overriding method can accept the callback and pass the created socket/stream to it (e.g., callback(null, newSocket)). If an error occurs during socket creation, it should be passed as the first argument to the callback (e.g., callback(err)).

The agent will call the provided createConnection function with options and this internal callback. The callback provided by the agent has a signature of (err, stream).

agent.keepSocketAlive(socket)#

Called when socket is detached from a request and could be persisted by the Agent. Default behavior is to:

socket.setKeepAlive(true, this.keepAliveMsecs);
socket.unref();
return true;
js

This method can be overridden by a particular Agent subclass. If this method returns a falsy value, the socket will be destroyed instead of persisting it for use with the next request.

The socket argument can be an instance of <net.Socket>, a subclass of <stream.Duplex>.

agent.reuseSocket(socket, request)#

Called when socket is attached to request after being persisted because of the keep-alive options. Default behavior is to:

socket.ref();
js

This method can be overridden by a particular Agent subclass.

The socket argument can be an instance of <net.Socket>, a subclass of <stream.Duplex>.

agent.destroy()#

Destroy any sockets that are currently in use by the agent.

It is usually not necessary to do this. However, if using an agent with keepAlive enabled, then it is best to explicitly shut down the agent when it is no longer needed. Otherwise, sockets might stay open for quite a long time before the server terminates them.

agent.freeSockets#

An object which contains arrays of sockets currently awaiting use by the agent when keepAlive is enabled. Do not modify.

Sockets in the freeSockets list will be automatically destroyed and removed from the array on 'timeout'.

agent.getName([options])#

  • options <Object> A set of options providing information for name generation
    • host <string> A domain name or IP address of the server to issue the request to
    • port <number> Port of remote server
    • localAddress <string> Local interface to bind for network connections when issuing the request
    • family <integer> Must be 4 or 6 if this doesn't equal undefined.
  • Returns: <string>

Get a unique name for a set of request options, to determine whether a connection can be reused. For an HTTP agent, this returns host:port:localAddress or host:port:localAddress:family. For an HTTPS agent, the name includes the CA, cert, ciphers, and other HTTPS/TLS-specific options that determine socket reusability.

agent.maxFreeSockets#

By default set to 256. For agents with keepAlive enabled, this sets the maximum number of sockets that will be left open in the free state.

agent.maxSockets#

By default set to Infinity. Determines how many concurrent sockets the agent can have open per origin. Origin is the returned value of agent.getName().

agent.maxTotalSockets#

By default set to Infinity. Determines how many concurrent sockets the agent can have open. Unlike maxSockets, this parameter applies across all origins.

agent.requests#

An object which contains queues of requests that have not yet been assigned to sockets. Do not modify.

agent.sockets#

An object which contains arrays of sockets currently in use by the agent. Do not modify.

Class: http.ClientRequest#

This object is created internally and returned from http.request(). It represents an in-progress request whose header has already been queued. The header is still mutable using the setHeader(name, value), getHeader(name), removeHeader(name) API. The actual header will be sent along with the first data chunk or when calling request.end().

To get the response, add a listener for 'response' to the request object. 'response' will be emitted from the request object when the response headers have been received. The 'response' event is executed with one argument which is an instance of http.IncomingMessage.

During the 'response' event, one can add listeners to the response object; particularly to listen for the 'data' event.

If no 'response' handler is added, then the response will be entirely discarded. However, if a 'response' event handler is added, then the data from the response object must be consumed, either by calling response.read() whenever there is a 'readable' event, or by adding a 'data' handler, or by calling the .resume() method. Until the data is consumed, the 'end' event will not fire. Also, until the data is read it will consume memory that can eventually lead to a 'process out of memory' error.

For backward compatibility, res will only emit 'error' if there is an 'error' listener registered.

Set Content-Length header to limit the response body size. If response.strictContentLength is set to true, mismatching the Content-Length header value will result in an Error being thrown, identified by code: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH'.

Content-Length value should be in bytes, not characters. Use Buffer.byteLength() to determine the length of the body in bytes.

Event: 'abort'#

Stability: 0 - Deprecated. Listen for the 'close' event instead.

Emitted when the request has been aborted by the client. This event is only emitted on the first call to abort().

Event: 'close'#

Indicates that the request is completed, or its underlying connection was terminated prematurely (before the response completion).

Event: 'connect'#

Emitted each time a server responds to a request with a CONNECT method. If this event is not being listened for, clients receiving a CONNECT method will have their connections closed.

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

A client and server pair demonstrating how to listen for the 'connect' event:

import { createServer, request } from 'node:http';
import { connect } from 'node:net';
import { URL } from 'node:url';

// Create an HTTP tunneling proxy
const proxy = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
  // Connect to an origin server
  const { port, hostname } = new URL(`http://${req.url}`);
  const serverSocket = connect(port || 80, hostname, () => {
    clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
                    'Proxy-agent: Node.js-Proxy\r\n' +
                    '\r\n');
    serverSocket.write(head);
    serverSocket.pipe(clientSocket);
    clientSocket.pipe(serverSocket);
  });
});

// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

  // Make a request to a tunneling proxy
  const options = {
    port: 1337,
    host: '127.0.0.1',
    method: 'CONNECT',
    path: 'www.google.com:80',
  };

  const req = request(options);
  req.end();

  req.on('connect', (res, socket, head) => {
    console.log('got connected!');

    // Make a request over an HTTP tunnel
    socket.write('GET / HTTP/1.1\r\n' +
                 'Host: www.google.com:80\r\n' +
                 'Connection: close\r\n' +
                 '\r\n');
    socket.on('data', (chunk) => {
      console.log(chunk.toString());
    });
    socket.on('end', () => {
      proxy.close();
    });
  });
});
const http = require('node:http');
const net = require('node:net');
const { URL } = require('node:url');

// Create an HTTP tunneling proxy
const proxy = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
proxy.on('connect', (req, clientSocket, head) => {
  // Connect to an origin server
  const { port, hostname } = new URL(`http://${req.url}`);
  const serverSocket = net.connect(port || 80, hostname, () => {
    clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
                    'Proxy-agent: Node.js-Proxy\r\n' +
                    '\r\n');
    serverSocket.write(head);
    serverSocket.pipe(clientSocket);
    clientSocket.pipe(serverSocket);
  });
});

// Now that proxy is running
proxy.listen(1337, '127.0.0.1', () => {

  // Make a request to a tunneling proxy
  const options = {
    port: 1337,
    host: '127.0.0.1',
    method: 'CONNECT',
    path: 'www.google.com:80',
  };

  const req = http.request(options);
  req.end();

  req.on('connect', (res, socket, head) => {
    console.log('got connected!');

    // Make a request over an HTTP tunnel
    socket.write('GET / HTTP/1.1\r\n' +
                 'Host: www.google.com:80\r\n' +
                 'Connection: close\r\n' +
                 '\r\n');
    socket.on('data', (chunk) => {
      console.log(chunk.toString());
    });
    socket.on('end', () => {
      proxy.close();
    });
  });
});
javascript

Event: 'continue'#

Emitted when the server sends a '100 Continue' HTTP response, usually because the request contained 'Expect: 100-continue'. This is an instruction that the client should send the request body.

Event: 'finish'#

Emitted when the request has been sent. More specifically, this event is emitted when the last segment of the request headers and body have been handed off to the operating system for transmission over the network. It does not imply that the server has received anything yet.

Event: 'information'#

Emitted when the server sends a 1xx intermediate response (excluding 101 Upgrade). The listeners of this event will receive an object containing the HTTP version, status code, status message, key-value headers object, and array with the raw header names followed by their respective values.

import { request } from 'node:http';

const options = {
  host: '127.0.0.1',
  port: 8080,
  path: '/length_request',
};

// Make a request
const req = request(options);
req.end();

req.on('information', (info) => {
  console.log(`Got information prior to main response: ${info.statusCode}`);
});
const http = require('node:http');

const options = {
  host: '127.0.0.1',
  port: 8080,
  path: '/length_request',
};

// Make a request
const req = http.request(options);
req.end();

req.on('information', (info) => {
  console.log(`Got information prior to main response: ${info.statusCode}`);
});
javascript

101 Upgrade statuses do not fire this event due to their break from the traditional HTTP request/response chain, such as web sockets, in-place TLS upgrades, or HTTP 2.0. To be notified of 101 Upgrade notices, listen for the 'upgrade' event instead.

Event: 'response'#

Emitted when a response is received to this request. This event is emitted only once.

Event: 'socket'#

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

Event: 'timeout'#

Emitted when the underlying socket times out from inactivity. This only notifies that the socket has been idle. The request must be destroyed manually.

See also: request.setTimeout().

Event: 'upgrade'#

Emitted each time a server responds to a request with an upgrade. If this event is not being listened for and the response status code is 101 Switching Protocols, clients receiving an upgrade header will have their connections closed.

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

A client server pair demonstrating how to listen for the 'upgrade' event.

import http from 'node:http';
import process from 'node:process';

// Create an HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
server.on('upgrade', (req, stream, head) => {
  stream.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
               'Upgrade: WebSocket\r\n' +
               'Connection: Upgrade\r\n' +
               '\r\n');

  stream.pipe(stream); // echo back
});

// Now that server is running
server.listen(1337, '127.0.0.1', () => {

  // make a request
  const options = {
    port: 1337,
    host: '127.0.0.1',
    headers: {
      'Connection': 'Upgrade',
      'Upgrade': 'websocket',
    },
  };

  const req = http.request(options);
  req.end();

  req.on('upgrade', (res, stream, upgradeHead) => {
    console.log('got upgraded!');
    stream.end();
    process.exit(0);
  });
});
const http = require('node:http');

// Create an HTTP server
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('okay');
});
server.on('upgrade', (req, stream, head) => {
  stream.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
               'Upgrade: WebSocket\r\n' +
               'Connection: Upgrade\r\n' +
               '\r\n');

  stream.pipe(stream); // echo back
});

// Now that server is running
server.listen(1337, '127.0.0.1', () => {

  // make a request
  const options = {
    port: 1337,
    host: '127.0.0.1',
    headers: {
      'Connection': 'Upgrade',
      'Upgrade': 'websocket',
    },
  };

  const req = http.request(options);
  req.end();

  req.on('upgrade', (res, stream, upgradeHead) => {
    console.log('got upgraded!');
    stream.end();
    process.exit(0);
  });
});
javascript

request.abort()#

Stability: 0 - Deprecated: Use request.destroy() instead.

Marks the request as aborting. Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.

request.aborted#

Stability: 0 - Deprecated. Check request.destroyed instead.

The request.aborted property will be true if the request has been aborted.

request.connection#

Stability: 0 - Deprecated. Use request.socket.

See request.socket.

request.cork()#

See writable.cork().

request.end([data[, encoding]][, callback])#

Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.

request.destroy([error])#

  • error <Error> Optional, an error to emit with 'error' event.
  • Returns: <this>

Destroy the request. Optionally emit an 'error' event, and emit a 'close' event. Calling this will cause remaining data in the response to be dropped, and the socket to be destroyed if used, or returned to the corresponding Agent pool otherwise if possible.

See writable.destroy() for further details.

request.destroyed#

Is true after request.destroy() has been called.

See writable.destroyed for further details.

request.finished#

Stability: 0 - Deprecated. Use request.writableEnded.

The request.finished property will be true if request.end() has been called. request.end() will automatically be called if the request was initiated via http.get().

request.flushHeaders()#

Flushes the request headers.

For efficiency reasons, Node.js normally buffers the request headers until request.end() is called or the first chunk of request data is written. It then tries to pack the request headers and data into a single TCP packet.

That's usually desired (it saves a TCP round-trip), but not when the first data is not sent until possibly much later. request.flushHeaders() bypasses the optimization and kickstarts the request.

request.getHeader(name)#

Reads out a header on the request. The name is case-insensitive. The type of the return value depends on the arguments provided to request.setHeader().

request.setHeader('content-type', 'text/html');
request.setHeader('Content-Length', Buffer.byteLength(body));
request.setHeader('Cookie', ['type=ninja', 'language=javascript']);
const contentType = request.getHeader('Content-Type');
// 'contentType' is 'text/html'
const contentLength = request.getHeader('Content-Length');
// 'contentLength' is of type number
const cookie = request.getHeader('Cookie');
// 'cookie' is of type string[]
js

request.getHeaderNames()#

Returns an array containing the unique names of the current outgoing headers. All header names are lowercase.

request.setHeader('Foo', 'bar');
request.setHeader('Cookie', ['foo=bar', 'bar=baz']);

const headerNames = request.getHeaderNames();
// headerNames === ['foo', 'cookie']
js

request.getHeaders()#

Returns a shallow copy of the current outgoing headers. Since a shallow copy is used, array values may be mutated without additional calls to various header-related http module methods. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.

The object returned by the request.getHeaders() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.

request.setHeader('Foo', 'bar');
request.setHeader('Cookie', ['foo=bar', 'bar=baz']);

const headers = request.getHeaders();
// headers === { foo: 'bar', 'cookie': ['foo=bar', 'bar=baz'] }
js

request.getRawHeaderNames()#

Returns an array containing the unique names of the current outgoing raw headers. Header names are returned with their exact casing being set.

request.setHeader('Foo', 'bar');
request.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headerNames = request.getRawHeaderNames();
// headerNames === ['Foo', 'Set-Cookie']
js

request.hasHeader(name)#

Returns true if the header identified by name is currently set in the outgoing headers. The header name matching is case-insensitive.

const hasContentType = request.hasHeader('content-type');
js

request.maxHeadersCount#

Limits maximum response headers count. If set to 0, no limit will be applied.

request.path#

request.method#

request.host#

request.protocol#

request.removeHeader(name)#

Removes a header that's already defined into headers object.

request.removeHeader('Content-Type');
js

request.reusedSocket#

  • Type: <boolean> Whether the request is send through a reused socket.

When sending request through a keep-alive enabled agent, the underlying socket might be reused. But if server closes connection at unfortunate time, client may run into a 'ECONNRESET' error.

import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });

// Server has a 5 seconds keep-alive timeout by default
http
  .createServer((req, res) => {
    res.write('hello\n');
    res.end();
  })
  .listen(3000);

setInterval(() => {
  // Adapting a keep-alive agent
  http.get('http://localhost:3000', { agent }, (res) => {
    res.on('data', (data) => {
      // Do nothing
    });
  });
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeout
const http = require('node:http');
const agent = new http.Agent({ keepAlive: true });

// Server has a 5 seconds keep-alive timeout by default
http
  .createServer((req, res) => {
    res.write('hello\n');
    res.end();
  })
  .listen(3000);

setInterval(() => {
  // Adapting a keep-alive agent
  http.get('http://localhost:3000', { agent }, (res) => {
    res.on('data', (data) => {
      // Do nothing
    });
  });
}, 5000); // Sending request on 5s interval so it's easy to hit idle timeout
javascript

By marking a request whether it reused socket or not, we can do automatic error retry base on it.

import http from 'node:http';
const agent = new http.Agent({ keepAlive: true });

function retriableRequest() {
  const req = http
    .get('http://localhost:3000', { agent }, (res) => {
      // ...
    })
    .on('error', (err) => {
      // Check if retry is needed
      if (req.reusedSocket && err.code === 'ECONNRESET') {
        retriableRequest();
      }
    });
}

retriableRequest();
const http = require('node:http');
const agent = new http.Agent({ keepAlive: true });

function retriableRequest() {
  const req = http
    .get('http://localhost:3000', { agent }, (res) => {
      // ...
    })
    .on('error', (err) => {
      // Check if retry is needed
      if (req.reusedSocket && err.code === 'ECONNRESET') {
        retriableRequest();
      }
    });
}

retriableRequest();
javascript

request.setHeader(name, value)#

Sets a single header value for headers object. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name. Non-string values will be stored without modification. Therefore, request.getHeader() may return non-string values. However, the non-string values will be converted to strings for network transmission.

request.setHeader('Content-Type', 'application/json');
js

or

request.setHeader('Cookie', ['type=ninja', 'language=javascript']);
js

When the value is a string an exception will be thrown if it contains characters outside the latin1 encoding.

If you need to pass UTF-8 characters in the value please encode the value using the RFC 8187 standard.

const filename = 'Rock 🎵.txt';
request.setHeader('Content-Disposition', `attachment; filename*=utf-8''${encodeURIComponent(filename)}`);
js

request.setNoDelay([noDelay])#

Once a socket is assigned to this request and is connected socket.setNoDelay() will be called.

request.setSocketKeepAlive([enable][, initialDelay])#

Once a socket is assigned to this request and is connected socket.setKeepAlive() will be called.

request.setTimeout(timeout[, callback])#

  • timeout <number> Milliseconds before a request times out.
  • callback <Function> Optional function to be called when a timeout occurs. Same as binding to the 'timeout' event.
  • Returns: <http.ClientRequest>

Once a socket is assigned to this request and is connected socket.setTimeout() will be called.

request.socket#

Reference to the underlying socket. Usually users will not want to access this property. In particular, the socket will not emit 'readable' events because of how the protocol parser attaches to the socket.

import http from 'node:http';
const options = {
  host: 'www.google.com',
};
const req = http.get(options);
req.end();
req.once('response', (res) => {
  const ip = req.socket.localAddress;
  const port = req.socket.localPort;
  console.log(`Your IP address is ${ip} and your source port is ${port}.`);
  // Consume response object
});
const http = require('node:http');
const options = {
  host: 'www.google.com',
};
const req = http.get(options);
req.end();
req.once('response', (res) => {
  const ip = req.socket.localAddress;
  const port = req.socket.localPort;
  console.log(`Your IP address is ${ip} and your source port is ${port}.`);
  // Consume response object
});
javascript

This property is guaranteed to be an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specified a socket type other than <net.Socket>.

request.uncork()#

See writable.uncork().

request.writableEnded#

Is true after request.end() has been called. This property does not indicate whether the data has been flushed, for this use request.writableFinished instead.

request.writableFinished#

Is true if all data has been flushed to the underlying system, immediately before the 'finish' event is emitted.

request.write(chunk[, encoding][, callback])#

Sends a chunk of the body. This method can be called multiple times. If no Content-Length is set, data will automatically be encoded in HTTP Chunked transfer encoding, so that server knows when the data ends. The Transfer-Encoding: chunked header is added. Calling request.end() is necessary to finish sending the request.

The encoding argument is optional and only applies when chunk is a string. Defaults to 'utf8'.

The callback argument is optional and will be called when this chunk of data is flushed, but only if the chunk is non-empty.

Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is free again.

When write function is called with empty string or buffer, it does nothing and waits for more input.

Class: http.Server#

Event: 'checkContinue'#

Emitted each time a request with an HTTP Expect: 100-continue is received. If this event is not listened for, the server will automatically respond with a 100 Continue as appropriate.

Handling this event involves calling response.writeContinue() if the client should continue to send the request body, or generating an appropriate HTTP response (e.g. 400 Bad Request) if the client should not continue to send the request body.

When this event is emitted and handled, the 'request' event will not be emitted.

Event: 'checkExpectation'#

Emitted each time a request with an HTTP Expect header is received, where the value is not 100-continue. If this event is not listened for, the server will automatically respond with a 417 Expectation Failed as appropriate.

When this event is emitted and handled, the 'request' event will not be emitted.

Event: 'clientError'#

If a client connection emits an 'error' event, it will be forwarded here. Listener of this event is responsible for closing/destroying the underlying socket. For example, one may wish to more gracefully close the socket with a custom HTTP response instead of abruptly severing the connection. The socket must be closed or destroyed before the listener ends.

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

Default behavior is to try close the socket with an HTTP '400 Bad Request', or an HTTP '431 Request Header Fields Too Large' in the case of an HPE_HEADER_OVERFLOW error. If the socket is not writable or headers of the current attached http.ServerResponse has been sent, it is immediately destroyed.

socket is the net.Socket object that the error originated from.

import http from 'node:http';

const server = http.createServer((req, res) => {
  res.end();
});
server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
const http = require('node:http');

const server = http.createServer((req, res) => {
  res.end();
});
server.on('clientError', (err, socket) => {
  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
javascript

When the 'clientError' event occurs, there is no request or response object, so any HTTP response sent, including response headers and payload, must be written directly to the socket object. Care must be taken to ensure the response is a properly formatted HTTP response message.

err is an instance of Error with two extra columns:

  • bytesParsed: the bytes count of request packet that Node.js may have parsed correctly;
  • rawPacket: the raw packet of current request.

In some cases, the client has already received the response and/or the socket has already been destroyed, like in case of ECONNRESET errors. Before trying to send data to the socket, it is better to check that it is still writable.

server.on('clientError', (err, socket) => {
  if (err.code === 'ECONNRESET' || !socket.writable) {
    return;
  }

  socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
js

Event: 'close'#

Emitted when the server closes.

Event: 'connect'#

Emitted each time a client requests an HTTP CONNECT method. If this event is not listened for, then clients requesting a CONNECT method will have their connections closed.

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

After this event is emitted, the request's socket will not have a 'data' event listener, meaning it will need to be bound in order to handle data sent to the server on that socket.

Event: 'connection'#

This event is emitted when a new TCP stream is established. socket is typically an object of type net.Socket. Usually users will not want to access this event. In particular, the socket will not emit 'readable' events because of how the protocol parser attaches to the socket. The socket can also be accessed at request.socket.

This event can also be explicitly emitted by users to inject connections into the HTTP server. In that case, any Duplex stream can be passed.

If socket.setTimeout() is called here, the timeout will be replaced with server.keepAliveTimeout when the socket has served a request (if server.keepAliveTimeout is non-zero).

This event is guaranteed to be passed an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specifies a socket type other than <net.Socket>.

Event: 'dropRequest'#

When the number of requests on a socket reaches the threshold of server.maxRequestsPerSocket, the server will drop new requests and emit 'dropRequest' event instead, then send 503 to client.

Event: 'request'#

Emitted each time there is a request. There may be multiple requests per connection (in the case of HTTP Keep-Alive connections).

Event: 'upgrade'#

Emitted each time a client's HTTP upgrade request is accepted. By default all HTTP upgrade requests are ignored (i.e. only regular 'request' events are emitted, sticking with the normal HTTP request/response flow) unless you listen to this event, in which case they are all accepted (i.e. the 'upgrade' event is emitted instead, and future communication must handled directly through the raw stream). You can control this more precisely by using the server shouldUpgradeCallback option.

Listening to this event is optional and clients cannot insist on a protocol change.

If an upgrade is accepted by shouldUpgradeCallback but no event handler is registered then the socket will be destroyed, resulting in an immediate connection closure for the client.

In the uncommon case that the incoming request has a body, this body will be parsed as normal, separate to the upgrade stream, and the raw stream data will only begin after it has completed. To ensure that reading from the stream isn't blocked by waiting for the request body to be read, any reads on the stream will start the request body flowing automatically. If you want to read the request body, ensure that you do so (i.e. you attach 'data' listeners) before starting to read from the upgraded stream.

The stream argument will typically be the <net.Socket> instance used by the request, but in some cases (such as with a request body) it may be a duplex stream. If required, you can access the raw connection underlying the request via request.socket, which is guaranteed to be an instance of <net.Socket> unless the user specified another socket type.

server.close([callback])#

Stops the server from accepting new connections and closes all connections connected to this server which are not sending a request or waiting for a response. See net.Server.close().

const http = require('node:http');

const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
}, 10000);
js

server.closeAllConnections()#

Closes all established HTTP(S) connections connected to this server, including active connections connected to this server which are sending a request or waiting for a response. This does not destroy sockets upgraded to a different protocol, such as WebSocket or HTTP/2.

This is a forceful way of closing all connections and should be used with caution. Whenever using this in conjunction with server.close, calling this after server.close is recommended as to avoid race conditions where new connections are created between a call to this and a call to server.close.

const http = require('node:http');

const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
  // Closes all connections, ensuring the server closes successfully
  server.closeAllConnections();
}, 10000);
js

server.closeIdleConnections()#

Closes all connections connected to this server which are not sending a request or waiting for a response.

Starting with Node.js 19.0.0, there's no need for calling this method in conjunction with server.close to reap keep-alive connections. Using it won't cause any harm though, and it can be useful to ensure backwards compatibility for libraries and applications that need to support versions older than 19.0.0. Whenever using this in conjunction with server.close, calling this after server.close is recommended as to avoid race conditions where new connections are created between a call to this and a call to server.close.

const http = require('node:http');

const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
// Close the server after 10 seconds
setTimeout(() => {
  server.close(() => {
    console.log('server on port 8000 closed successfully');
  });
  // Closes idle connections, such as keep-alive connections. Server will close
  // once remaining active connections are terminated
  server.closeIdleConnections();
}, 10000);
js

server.headersTimeout#

Limit the amount of time the parser will wait to receive the complete HTTP headers.

If the timeout expires, the server responds with status 408 without forwarding the request to the request listener and then closes the connection.

It must be set to a non-zero value (e.g. 120 seconds) to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front.

server.listen()#

Starts the HTTP server listening for connections. This method is identical to server.listen() from net.Server.

server.listening#

  • Type: <boolean> Indicates whether or not the server is listening for connections.

server.maxHeadersCount#

Limits maximum incoming headers count. If set to 0, no limit will be applied.

server.requestTimeout#

Sets the timeout value in milliseconds for receiving the entire request from the client.

If the timeout expires, the server responds with status 408 without forwarding the request to the request listener and then closes the connection.

It must be set to a non-zero value (e.g. 120 seconds) to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front.

server.setTimeout([msecs][, callback])#

Sets the timeout value for sockets, and emits a 'timeout' event on the Server object, passing the socket as an argument, if a timeout occurs.

If there is a 'timeout' event listener on the Server object, then it will be called with the timed-out socket as an argument.

By default, the Server does not timeout sockets. However, if a callback is assigned to the Server's 'timeout' event, timeouts must be handled explicitly.

server.maxRequestsPerSocket#

  • Type: <number> Requests per socket. Default: 0 (no limit)

The maximum number of requests socket can handle before closing keep alive connection.

A value of 0 will disable the limit.

When the limit is reached it will set the Connection header value to close, but will not actually close the connection, subsequent requests sent after the limit is reached will get 503 Service Unavailable as a response.

server.timeout#

  • Type: <number> Timeout in milliseconds. Default: 0 (no timeout)

The number of milliseconds of inactivity before a socket is presumed to have timed out.

A value of 0 will disable the timeout behavior on incoming connections.

The socket timeout logic is set up on connection, so changing this value only affects new connections to the server, not any existing connections.

server.keepAliveTimeout#

  • Type: <number> Timeout in milliseconds. Default: 5000 (5 seconds).

The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed.

This timeout value is combined with the server.keepAliveTimeoutBuffer option to determine the actual socket timeout, calculated as: socketTimeout = keepAliveTimeout + keepAliveTimeoutBuffer If the server receives new data before the keep-alive timeout has fired, it will reset the regular inactivity timeout, i.e., server.timeout.

A value of 0 will disable the keep-alive timeout behavior on incoming connections. A value of 0 makes the HTTP server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.

The socket timeout logic is set up on connection, so changing this value only affects new connections to the server, not any existing connections.

server.keepAliveTimeoutBuffer#

  • Type: <number> Timeout in milliseconds. Default: 1000 (1 second).

An additional buffer time added to the server.keepAliveTimeout to extend the internal socket timeout.

This buffer helps reduce connection reset (ECONNRESET) errors by increasing the socket timeout slightly beyond the advertised keep-alive timeout.

This option applies only to new incoming connections.

server[Symbol.asyncDispose]()#

Calls server.close() and returns a promise that fulfills when the server has closed.

Class: http.ServerResponse#

This object is created internally by an HTTP server, not by the user. It is passed as the second parameter to the 'request' event.

Event: 'close'#

Indicates that the response is completed, or its underlying connection was terminated prematurely (before the response completion).

Event: 'finish'#

Emitted when the response has been sent. More specifically, this event is emitted when the last segment of the response headers and body have been handed off to the operating system for transmission over the network. It does not imply that the client has received anything yet.

response.addTrailers(headers)#

This method adds HTTP trailing headers (a header but at the end of the message) to the response.

Trailers will only be emitted if chunked encoding is used for the response; if it is not (e.g. if the request was HTTP/1.0), they will be silently discarded.

HTTP requires the Trailer header to be sent in order to emit trailers, with a list of the header fields in its value. E.g.,

response.writeHead(200, { 'Content-Type': 'text/plain',
                          'Trailer': 'Content-MD5' });
response.write(fileData);
response.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' });
response.end();
js

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

response.connection#

Stability: 0 - Deprecated. Use response.socket.

See response.socket.

response.cork()#

See writable.cork().

response.end([data[, encoding]][, callback])#

This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete. The method, response.end(), MUST be called on each response.

If data is specified, it is similar in effect to calling response.write(data, encoding) followed by response.end(callback).

If callback is specified, it will be called when the response stream is finished.

response.finished#

Stability: 0 - Deprecated. Use response.writableEnded.

The response.finished property will be true if response.end() has been called.

response.flushHeaders()#

Flushes the response headers. See also: request.flushHeaders().

response.getHeader(name)#

Reads out a header that's already been queued but not sent to the client. The name is case-insensitive. The type of the return value depends on the arguments provided to response.setHeader().

response.setHeader('Content-Type', 'text/html');
response.setHeader('Content-Length', Buffer.byteLength(body));
response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
const contentType = response.getHeader('content-type');
// contentType is 'text/html'
const contentLength = response.getHeader('Content-Length');
// contentLength is of type number
const setCookie = response.getHeader('set-cookie');
// setCookie is of type string[]
js

response.getHeaderNames()#

Returns an array containing the unique names of the current outgoing headers. All header names are lowercase.

response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headerNames = response.getHeaderNames();
// headerNames === ['foo', 'set-cookie']
js

response.getHeaders()#

Returns a shallow copy of the current outgoing headers. Since a shallow copy is used, array values may be mutated without additional calls to various header-related http module methods. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.

The object returned by the response.getHeaders() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.

response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headers = response.getHeaders();
// headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }
js

response.hasHeader(name)#

Returns true if the header identified by name is currently set in the outgoing headers. The header name matching is case-insensitive.

const hasContentType = response.hasHeader('content-type');
js

response.headersSent#

Boolean (read-only). True if headers were sent, false otherwise.

response.removeHeader(name)#

Removes a header that's queued for implicit sending.

response.removeHeader('Content-Encoding');
js

response.req#

A reference to the original HTTP request object.

response.sendDate#

When true, the Date header will be automatically generated and sent in the response if it is not already present in the headers. Defaults to true.

This should only be disabled for testing; the Date header is required in most HTTP responses (see RFC 9110 Section 6.6.1 for details).

response.setHeader(name, value)#

Returns the response object.

Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name. Non-string values will be stored without modification. Therefore, response.getHeader() may return non-string values. However, the non-string values will be converted to strings for network transmission. The same response object is returned to the caller, to enable call chaining.

response.setHeader('Content-Type', 'text/html');
js

or

response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
js

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

When headers have been set with response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.

// Returns content-type = text/plain
const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});
js

If response.writeHead() method is called and this method has not been called, it will directly write the supplied header values onto the network channel without caching internally, and the response.getHeader() on the header will not yield the expected result. If progressive population of headers is desired with potential future retrieval and modification, use response.setHeader() instead of response.writeHead().

response.setTimeout(msecs[, callback])#

Sets the Socket's timeout value to msecs. If a callback is provided, then it is added as a listener on the 'timeout' event on the response object.

If no 'timeout' listener is added to the request, the response, or the server, then sockets are destroyed when they time out. If a handler is assigned to the request, the response, or the server's 'timeout' events, timed out sockets must be handled explicitly.

response.socket#

Reference to the underlying socket. Usually users will not want to access this property. In particular, the socket will not emit 'readable' events because of how the protocol parser attaches to the socket. After response.end(), the property is nulled.

import http from 'node:http';
const server = http.createServer((req, res) => {
  const ip = res.socket.remoteAddress;
  const port = res.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);
const http = require('node:http');
const server = http.createServer((req, res) => {
  const ip = res.socket.remoteAddress;
  const port = res.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);
javascript

This property is guaranteed to be an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specified a socket type other than <net.Socket>.

response.statusCode#

When using implicit headers (not calling response.writeHead() explicitly), this property controls the status code that will be sent to the client when the headers get flushed.

response.statusCode = 404;
js

After response header was sent to the client, this property indicates the status code which was sent out.

response.statusMessage#

When using implicit headers (not calling response.writeHead() explicitly), this property controls the status message that will be sent to the client when the headers get flushed. If this is left as undefined then the standard message for the status code will be used.

response.statusMessage = 'Not found';
js

After response header was sent to the client, this property indicates the status message which was sent out.

response.strictContentLength#

If set to true, Node.js will check whether the Content-Length header value and the size of the body, in bytes, are equal. Mismatching the Content-Length header value will result in an Error being thrown, identified by code: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH'.

response.uncork()#

See writable.uncork().

response.writableEnded#

Is true after response.end() has been called. This property does not indicate whether the data has been flushed, for this use response.writableFinished instead.

response.writableFinished#

Is true if all data has been flushed to the underlying system, immediately before the 'finish' event is emitted.

response.write(chunk[, encoding][, callback])#

If this method is called and response.writeHead() has not been called, it will switch to implicit header mode and flush the implicit headers.

This sends a chunk of the response body. This method may be called multiple times to provide successive parts of the body.

If rejectNonStandardBodyWrites is set to true in createServer then writing to the body is not allowed when the request method or response status do not support content. If an attempt is made to write to the body for a HEAD request or as part of a 204 or 304response, a synchronous Error with the code ERR_HTTP_BODY_NOT_ALLOWED is thrown.

chunk can be a string or a buffer. If chunk is a string, the second parameter specifies how to encode it into a byte stream. callback will be called when this chunk of data is flushed.

This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used.

The first time response.write() is called, it will send the buffered header information and the first chunk of the body to the client. The second time response.write() is called, Node.js assumes data will be streamed, and sends the new data separately. That is, the response is buffered up to the first chunk of the body.

Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is free again.

response.writeContinue()#

Sends an HTTP/1.1 100 Continue message to the client, indicating that the request body should be sent. See the 'checkContinue' event on Server.

response.writeEarlyHints(hints[, callback])#

Sends an HTTP/1.1 103 Early Hints message to the client with a Link header, indicating that the user agent can preload/preconnect the linked resources. The hints is an object containing the values of headers to be sent with early hints message. The optional callback argument will be called when the response message has been written.

Example

const earlyHintsLink = '</styles.css>; rel=preload; as=style';
response.writeEarlyHints({
  'link': earlyHintsLink,
});

const earlyHintsLinks = [
  '</styles.css>; rel=preload; as=style',
  '</scripts.js>; rel=preload; as=script',
];
response.writeEarlyHints({
  'link': earlyHintsLinks,
  'x-trace-id': 'id for diagnostics',
});

const earlyHintsCallback = () => console.log('early hints message sent');
response.writeEarlyHints({
  'link': earlyHintsLinks,
}, earlyHintsCallback);
js

response.writeHead(statusCode[, statusMessage][, headers])#

Sends a response header to the request. The status code is a 3-digit HTTP status code, like 404. The last argument, headers, are the response headers. Optionally one can give a human-readable statusMessage as the second argument.

headers may be an Array where the keys and values are in the same list. It is not a list of tuples. So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values. The array is in the same format as request.rawHeaders.

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

const body = 'hello world';
response
  .writeHead(200, {
    'Content-Length': Buffer.byteLength(body),
    'Content-Type': 'text/plain',
  })
  .end(body);
js

This method must only be called once on a message and it must be called before response.end() is called.

If response.write() or response.end() are called before calling this, the implicit/mutable headers will be calculated and call this function.

When headers have been set with response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.

If this method is called and response.setHeader() has not been called, it will directly write the supplied header values onto the network channel without caching internally, and the response.getHeader() on the header will not yield the expected result. If progressive population of headers is desired with potential future retrieval and modification, use response.setHeader() instead.

// Returns content-type = text/plain
const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});
js

Content-Length is read in bytes, not characters. Use Buffer.byteLength() to determine the length of the body in bytes. Node.js will check whether Content-Length and the length of the body which has been transmitted are equal or not.

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

response.writeInformation(statusCode[, headers][, callback])#

  • statusCode <number> An HTTP 1xx informational status code, between 100 and 199 inclusive, excluding 101 (Switching Protocols) which is only available through the 'upgrade' event.
  • headers <Object> | <Array> An optional set of headers to send with the informational response. Accepts the same shapes as response.writeHead().
  • callback <Function> Optional, called once the message has been written to the socket.

Sends an arbitrary HTTP/1.1 1xx informational response to the client. This is a generic equivalent of response.writeContinue(), response.writeProcessing() and response.writeEarlyHints(), and can be called multiple times before the final response. After the final response headers have been sent (via response.writeHead() or an implicit header), calling this method throws ERR_HTTP_HEADERS_SENT.

Clients receive these responses via the 'information' event on http.ClientRequest.

response.writeInformation(110, { 'X-Progress': '50%' });
js

response.writeProcessing()#

Sends an HTTP/1.1 102 Processing message to the client, indicating that the request body should be sent.

Class: http.IncomingMessage#

An IncomingMessage object is created by http.Server or http.ClientRequest and passed as the first argument to the 'request' and 'response' event respectively. It may be used to access response status, headers, and data.

Different from its socket value which is a subclass of <stream.Duplex>, the IncomingMessage itself extends <stream.Readable> and is created separately to parse and emit the incoming HTTP headers and payload, as the underlying socket may be reused multiple times in case of keep-alive.

Event: 'aborted'#

Stability: 0 - Deprecated. Listen for 'close' event instead.

Emitted when the request has been aborted.

Event: 'close'#

Emitted when the request has been completed.

message.aborted#

Stability: 0 - Deprecated. Check message.destroyed from <stream.Readable>.

The message.aborted property will be true if the request has been aborted.

message.complete#

The message.complete property will be true if a complete HTTP message has been received and successfully parsed.

This property is particularly useful as a means of determining if a client or server fully transmitted a message before a connection was terminated:

const req = http.request({
  host: '127.0.0.1',
  port: 8080,
  method: 'POST',
}, (res) => {
  res.resume();
  res.on('end', () => {
    if (!res.complete)
      console.error(
        'The connection was terminated while the message was still being sent');
  });
});
js

message.connection#

Stability: 0 - Deprecated. Use message.socket.

Alias for message.socket.

message.destroy([error])#

Calls destroy() on the socket that received the IncomingMessage. If error is provided, an 'error' event is emitted on the socket and error is passed as an argument to any listeners on the event.

message.headers#

The request/response headers object.

Key-value pairs of header names and values. Header names are lower-cased.

// Prints something like:
//
// { 'user-agent': 'curl/7.22.0',
//   host: '127.0.0.1:8000',
//   accept: '*/*' }
console.log(request.headers);
js

Duplicates in raw headers are handled in the following ways, depending on the header name:

  • Duplicates of age, authorization, content-length, content-type, etag, expires, from, host, if-modified-since, if-unmodified-since, last-modified, location, max-forwards, proxy-authorization, referer, retry-after, server, or user-agent are discarded. To allow duplicate values of the headers listed above to be joined, use the option joinDuplicateHeaders in http.request() and http.createServer(). See RFC 9110 Section 5.3 for more information.
  • set-cookie is always an array. Duplicates are added to the array.
  • For duplicate cookie headers, the values are joined together with ; .
  • For all other headers, the values are joined together with , .

message.headersDistinct#

Similar to message.headers, but there is no join logic and the values are always arrays of strings, even for headers received just once.

// Prints something like:
//
// { 'user-agent': ['curl/7.22.0'],
//   host: ['127.0.0.1:8000'],
//   accept: ['*/*'] }
console.log(request.headersDistinct);
js

message.httpVersion#

In case of server request, the HTTP version sent by the client. In the case of client response, the HTTP version of the connected-to server. Probably either '1.1' or '1.0'.

Also message.httpVersionMajor is the first integer and message.httpVersionMinor is the second.

message.method#

Only valid for request obtained from http.Server.

The request method as a string. Read only. Examples: 'GET', 'DELETE'.

message.rawHeaders#

The raw request/response headers list exactly as they were received.

The keys and values are in the same list. It is not a list of tuples. So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values.

Header names are not lowercased, and duplicates are not merged.

// Prints something like:
//
// [ 'user-agent',
//   'this is invalid because there can be only one',
//   'User-Agent',
//   'curl/7.22.0',
//   'Host',
//   '127.0.0.1:8000',
//   'ACCEPT',
//   '*/*' ]
console.log(request.rawHeaders);
js

message.rawTrailers#

The raw request/response trailer keys and values exactly as they were received. Only populated at the 'end' event.

message.setTimeout(msecs[, callback])#

Calls message.socket.setTimeout(msecs, callback).

message.signal#

An <AbortSignal> that is aborted when the underlying socket closes or the request is destroyed. The signal is created lazily on first access — no <AbortController> is allocated for requests that never use this property.

This is useful for cancelling downstream asynchronous work such as database queries or fetch calls when a client disconnects mid-request.

import http from 'node:http';

http.createServer(async (req, res) => {
  try {
    const data = await fetch('https://example.com/api', { signal: req.signal });
    res.end(JSON.stringify(await data.json()));
  } catch (err) {
    if (err.name === 'AbortError') return;
    res.statusCode = 500;
    res.end('Internal Server Error');
  }
}).listen(3000);
const http = require('node:http');

http.createServer(async (req, res) => {
  try {
    const data = await fetch('https://example.com/api', { signal: req.signal });
    res.end(JSON.stringify(await data.json()));
  } catch (err) {
    if (err.name === 'AbortError') return;
    res.statusCode = 500;
    res.end('Internal Server Error');
  }
}).listen(3000);
javascript

message.socket#

The net.Socket object associated with the connection.

With HTTPS support, use request.socket.getPeerCertificate() to obtain the client's authentication details.

This property is guaranteed to be an instance of the <net.Socket> class, a subclass of <stream.Duplex>, unless the user specified a socket type other than <net.Socket> or internally nulled.

message.statusCode#

Only valid for response obtained from http.ClientRequest.

The 3-digit HTTP response status code. E.G. 404.

message.statusMessage#

Only valid for response obtained from http.ClientRequest.

The HTTP response status message (reason phrase). E.G. OK or Internal Server Error.

message.trailers#

The request/response trailers object. Only populated at the 'end' event.

message.trailersDistinct#

Similar to message.trailers, but there is no join logic and the values are always arrays of strings, even for headers received just once. Only populated at the 'end' event.

message.url#

Only valid for request obtained from http.Server.

Request URL string. This contains only the URL that is present in the actual HTTP request. Take the following request:

GET /status?name=ryan HTTP/1.1
Accept: text/plain
http

To parse the URL into its parts:

new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);
js

When request.url is '/status?name=ryan' and process.env.HOST is undefined:

$ node
> new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`);
URL {
  href: 'http://localhost/status?name=ryan',
  origin: 'http://localhost',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'localhost',
  hostname: 'localhost',
  port: '',
  pathname: '/status',
  search: '?name=ryan',
  searchParams: URLSearchParams { 'name' => 'ryan' },
  hash: ''
}
console

Ensure that you set process.env.HOST to the server's host name, or consider replacing this part entirely. If using req.headers.host, ensure proper validation is used, as clients may specify a custom Host header.

Class: http.OutgoingMessage#

This class serves as the parent class of http.ClientRequest and http.ServerResponse. It is an abstract outgoing message from the perspective of the participants of an HTTP transaction.

Event: 'drain'#

Emitted when the buffer of the message is free again.

Event: 'finish'#

Emitted when the transmission is finished successfully.

Event: 'prefinish'#

Emitted after outgoingMessage.end() is called. When the event is emitted, all data has been processed but not necessarily completely flushed.

outgoingMessage.addTrailers(headers)#

Adds HTTP trailers (headers but at the end of the message) to the message.

Trailers will only be emitted if the message is chunked encoded. If not, the trailers will be silently discarded.

HTTP requires the Trailer header to be sent to emit trailers, with a list of header field names in its value, e.g.

message.writeHead(200, { 'Content-Type': 'text/plain',
                         'Trailer': 'Content-MD5' });
message.write(fileData);
message.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' });
message.end();
js

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

outgoingMessage.appendHeader(name, value)#

Append a single header value to the header object.

If the value is an array, this is equivalent to calling this method multiple times.

If there were no previous values for the header, this is equivalent to calling outgoingMessage.setHeader(name, value).

Depending of the value of options.uniqueHeaders when the client request or the server were created, this will end up in the header being sent multiple times or a single time with values joined using ; .

outgoingMessage.connection#

Stability: 0 - Deprecated: Use outgoingMessage.socket instead.

Alias of outgoingMessage.socket.

outgoingMessage.cork()#

See writable.cork().

outgoingMessage.destroy([error])#

  • error <Error> Optional, an error to emit with error event
  • Returns: <this>

Destroys the message. Once a socket is associated with the message and is connected, that socket will be destroyed as well.

outgoingMessage.end(chunk[, encoding][, callback])#

Finishes the outgoing message. If any parts of the body are unsent, it will flush them to the underlying system. If the message is chunked, it will send the terminating chunk 0\r\n\r\n, and send the trailers (if any).

If chunk is specified, it is equivalent to calling outgoingMessage.write(chunk, encoding), followed by outgoingMessage.end(callback).

If callback is provided, it will be called when the message is finished (equivalent to a listener of the 'finish' event).

outgoingMessage.flushHeaders()#

Flushes the message headers.

For efficiency reason, Node.js normally buffers the message headers until outgoingMessage.end() is called or the first chunk of message data is written. It then tries to pack the headers and data into a single TCP packet.

It is usually desired (it saves a TCP round-trip), but not when the first data is not sent until possibly much later. outgoingMessage.flushHeaders() bypasses the optimization and kickstarts the message.

outgoingMessage.getHeader(name)#

Gets the value of the HTTP header with the given name. If that header is not set, the returned value will be undefined.

outgoingMessage.getHeaderNames()#

Returns an array containing the unique names of the current outgoing headers. All names are lowercase.

outgoingMessage.getHeaders()#

Returns a shallow copy of the current outgoing headers. Since a shallow copy is used, array values may be mutated without additional calls to various header-related HTTP module methods. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.

The object returned by the outgoingMessage.getHeaders() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.

outgoingMessage.setHeader('Foo', 'bar');
outgoingMessage.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headers = outgoingMessage.getHeaders();
// headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }
js

outgoingMessage.hasHeader(name)#

Returns true if the header identified by name is currently set in the outgoing headers. The header name is case-insensitive.

const hasContentType = outgoingMessage.hasHeader('content-type');
js

outgoingMessage.headersSent#

Read-only. true if the headers were sent, otherwise false.

outgoingMessage.pipe()#

Overrides the stream.pipe() method inherited from the legacy Stream class which is the parent class of http.OutgoingMessage.

Calling this method will throw an Error because outgoingMessage is a write-only stream.

outgoingMessage.removeHeader(name)#

Removes a header that is queued for implicit sending.

outgoingMessage.removeHeader('Content-Encoding');
js

outgoingMessage.setHeader(name, value)#

Sets a single header value. If the header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings to send multiple headers with the same name.

outgoingMessage.setHeaders(headers)#

Sets multiple header values for implicit headers. headers must be an instance of Headers or Map, if a header already exists in the to-be-sent headers, its value will be replaced.

const headers = new Headers({ foo: 'bar' });
outgoingMessage.setHeaders(headers);
js

or

const headers = new Map([['foo', 'bar']]);
outgoingMessage.setHeaders(headers);
js

When headers have been set with outgoingMessage.setHeaders(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.

// Returns content-type = text/plain
const server = http.createServer((req, res) => {
  const headers = new Headers({ 'Content-Type': 'text/html' });
  res.setHeaders(headers);
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('ok');
});
js

outgoingMessage.setTimeout(msecs[, callback])#

  • msecs <number>
  • callback <Function> Optional function to be called when a timeout occurs. Same as binding to the timeout event.
  • Returns: <this>

Once a socket is associated with the message and is connected, socket.setTimeout() will be called with msecs as the first parameter.

outgoingMessage.socket#

Reference to the underlying socket. Usually, users will not want to access this property.

After calling outgoingMessage.end(), this property will be nulled.

outgoingMessage.uncork()#

See writable.uncork()

outgoingMessage.writableCorked#

The number of times outgoingMessage.cork() has been called.

outgoingMessage.writableEnded#

Is true if outgoingMessage.end() has been called. This property does not indicate whether the data has been flushed. For that purpose, use message.writableFinished instead.

outgoingMessage.writableFinished#

Is true if all data has been flushed to the underlying system.

outgoingMessage.writableHighWaterMark#

The highWaterMark of the underlying socket if assigned. Otherwise, the default buffer level when writable.write() starts returning false (16384).

outgoingMessage.writableLength#

The number of buffered bytes.

outgoingMessage.writableObjectMode#

Always false.

outgoingMessage.write(chunk[, encoding][, callback])#

Sends a chunk of the body. This method can be called multiple times.

The encoding argument is only relevant when chunk is a string. Defaults to 'utf8'.

The callback argument is optional and will be called when this chunk of data is flushed.

Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in the user memory. The 'drain' event will be emitted when the buffer is free again.

http.METHODS#

A list of the HTTP methods that are supported by the parser.

http.STATUS_CODES#

A collection of all the standard HTTP response status codes, and the short description of each. For example, http.STATUS_CODES[404] === 'Not Found'.

http.createServer([options][, requestListener])#

  • options <Object>

    • connectionsCheckingInterval: Sets the interval value in milliseconds to check for request and headers timeout in incomplete requests. Default: 30000.
    • headersTimeout: Sets the timeout value in milliseconds for receiving the complete HTTP headers from the client. See server.headersTimeout for more information. Default: 60000.
    • highWaterMark <number> Optionally overrides all sockets' readableHighWaterMark and writableHighWaterMark. This affects highWaterMark property of both IncomingMessage and ServerResponse. Default: See stream.getDefaultHighWaterMark().
    • httpValidation <string> Controls HTTP header value validation strictness for incoming requests. Accepted values are:
      • 'strict': Strictest validation; rejects any non-ASCII or control characters in header values.
      • 'relaxed': Allows a limited set of non-ASCII characters in header values, aligning with the Fetch specification.
      • 'insecure': Disables all header value validation (equivalent to insecureHTTPParser: true). Cannot be used together with insecureHTTPParser. Default: 'strict'.
    • insecureHTTPParser <boolean> If set to true, it will use an HTTP parser with leniency flags enabled. Using the insecure parser should be avoided. See --insecure-http-parser for more information. Default: false.
    • IncomingMessage <http.IncomingMessage> Specifies the IncomingMessage class to be used. Useful for extending the original IncomingMessage. Default: IncomingMessage.
    • joinDuplicateHeaders <boolean> If set to true, this option allows joining the field line values of multiple headers in a request with a comma (, ) instead of discarding the duplicates. For more information, refer to message.headers. Default: false.
    • keepAlive <boolean> If set to true, it enables keep-alive functionality on the socket immediately after a new incoming connection is received, similarly on what is done in socket.setKeepAlive(). Default: false.
    • keepAliveInitialDelay <number> If set to a positive number, it sets the initial delay before the first keepalive probe is sent on an idle socket. Default: 0.
    • keepAliveTimeout: The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. See server.keepAliveTimeout for more information. Default: 65000.
    • maxHeaderSize <number> Optionally overrides the value of --max-http-header-size for requests received by this server, i.e. the maximum length of request headers in bytes. Default: 16384 (16 KiB).
    • noDelay <boolean> If set to true, it disables the use of Nagle's algorithm immediately after a new incoming connection is received. Default: true.
    • requestTimeout: Sets the timeout value in milliseconds for receiving the entire request from the client. See server.requestTimeout for more information. Default: 300000.
    • requireHostHeader <boolean> If set to true, it forces the server to respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header (as mandated by the specification). Default: true.
    • ServerResponse <http.ServerResponse> Specifies the ServerResponse class to be used. Useful for extending the original ServerResponse. Default: ServerResponse.
    • shouldUpgradeCallback(request) <Function> A callback which receives an incoming request and returns a boolean, to control which upgrade attempts should be accepted. Accepted upgrades will fire an 'upgrade' event (or their sockets will be destroyed, if no listener is registered) while rejected upgrades will fire a 'request' event like any non-upgrade request. This options defaults to () => server.listenerCount('upgrade') > 0.
    • uniqueHeaders <Array> A list of response headers that should be sent only once. If the header's value is an array, the items will be joined using ; .
    • rejectNonStandardBodyWrites <boolean> If set to true, an error is thrown when writing to an HTTP response which does not have a body. Default: false.
    • optimizeEmptyRequests <boolean> If set to true, requests without Content-Length or Transfer-Encoding headers (indicating no body) will be initialized with an already-ended body stream, so they will never emit any stream events (like 'data' or 'end'). You can use req.readableEnded to detect this case. Default: false.
  • requestListener <Function>

  • Returns: <http.Server>

Returns a new instance of http.Server.

The requestListener is a function which is automatically added to the 'request' event.

import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
javascript
import http from 'node:http';

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer();

// Listen to the request event
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
javascript

http.get(options[, callback])#

http.get(url[, options][, callback])#

Since most requests are GET requests without bodies, Node.js provides this convenience method. The only difference between this method and http.request() is that it sets the method to GET by default and calls req.end() automatically. The callback must take care to consume the response data for reasons stated in http.ClientRequest section.

The callback is invoked with a single argument that is an instance of http.IncomingMessage.

JSON fetching example:

http.get('http://localhost:8000/', (res) => {
  const { statusCode } = res;
  const contentType = res.headers['content-type'];

  let error;
  // Any 2xx status code signals a successful response but
  // here we're only checking for 200.
  if (statusCode !== 200) {
    error = new Error('Request Failed.\n' +
                      `Status Code: ${statusCode}`);
  } else if (!/^application\/json/.test(contentType)) {
    error = new Error('Invalid content-type.\n' +
                      `Expected application/json but received ${contentType}`);
  }
  if (error) {
    console.error(error.message);
    // Consume response data to free up memory
    res.resume();
    return;
  }

  res.setEncoding('utf8');
  let rawData = '';
  res.on('data', (chunk) => { rawData += chunk; });
  res.on('end', () => {
    try {
      const parsedData = JSON.parse(rawData);
      console.log(parsedData);
    } catch (e) {
      console.error(e.message);
    }
  });
}).on('error', (e) => {
  console.error(`Got error: ${e.message}`);
});

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);
js

http.globalAgent#

Global instance of Agent which is used as the default for all HTTP client requests. Diverges from a default Agent configuration by having keepAlive enabled and a timeout of 5 seconds.

http.maxHeaderSize#

Read-only property specifying the maximum allowed size of HTTP headers in bytes. Defaults to 16 KiB. Configurable using the --max-http-header-size CLI option.

This can be overridden for servers and client requests by passing the maxHeaderSize option.

http.request(options[, callback])#

http.request(url[, options][, callback])#

  • url <string> | <URL>
  • options <Object>
    • agent <http.Agent> | <boolean> Controls Agent behavior. Possible values:
      • undefined (default): use http.globalAgent for this host and port.
      • Agent object: explicitly use the passed in Agent.
      • false: causes a new Agent with default values to be used.
    • auth <string> Basic authentication ('user:password') to compute an Authorization header.
    • createConnection <Function> A function that produces a socket/stream to use for the request when the agent option is not used. This can be used to avoid creating a custom Agent class just to override the default createConnection function. See agent.createConnection() for more details. Any Duplex stream is a valid return value.
    • defaultPort <number> Default port for the protocol. Default: agent.defaultPort if an Agent is used, else undefined.
    • family <number> IP address family to use when resolving host or hostname. Valid values are 4 or 6. When unspecified, both IP v4 and v6 will be used.
    • headers <Object> | <Array> An object or an array of strings containing request headers. The array is in the same format as message.rawHeaders.
    • hints <number> Optional dns.lookup() hints.
    • host <string> A domain name or IP address of the server to issue the request to. Default: 'localhost'.
    • hostname <string> Alias for host. To support url.parse(), hostname will be used if both host and hostname are specified.
    • httpValidation <string> Controls HTTP header value validation strictness for outgoing requests. Accepted values are:
      • 'strict': Strictest validation; rejects any non-ASCII or control characters in header values.
      • 'relaxed': Allows a limited set of non-ASCII characters in header values, aligning with the Fetch specification.
      • 'insecure': Disables all header value validation (equivalent to insecureHTTPParser: true). Cannot be used together with insecureHTTPParser. Default: 'strict'.
    • insecureHTTPParser <boolean> If set to true, it will use an HTTP parser with leniency flags enabled. Using the insecure parser should be avoided. See --insecure-http-parser for more information. Default: false
    • joinDuplicateHeaders <boolean> It joins the field line values of multiple headers in a request with , instead of discarding the duplicates. See message.headers for more information. Default: false.
    • localAddress <string> Local interface to bind for network connections.
    • localPort <number> Local port to connect from.
    • lookup <Function> Custom lookup function. Default: dns.lookup().
    • maxHeaderSize <number> Optionally overrides the value of --max-http-header-size (the maximum length of response headers in bytes) for responses received from the server. Default: 16384 (16 KiB).
    • method <string> A string specifying the HTTP request method. Default: 'GET'.
    • path <string> Request path. Should include query string if any. E.G. '/index.html?page=12'. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future. Default: '/'. The content in path is sent as the request target in the HTTP 1.1 message. When path is an absolute URL, this means the request target in the message in absolute form. If the receiving server is a proxy, the server typically forwards the request to the destination specified in the request target, and ignores the Host header. The user needs to make sure that path, host and the Host headers conform to the requirement of the request target in the HTTP specification. When the receiving server is known to be a proxy because the request is routed through Built-in Proxy Support, http.request will additionally perform a best-effort check to see that the host option or Host in headers agrees with the authority in path during the initial construction of the request. It gives up rewriting the request target for proxying and throws an error if they don't match at request construction time, though there won't be checks for later header mutations done by the user.
    • port <number> Port of remote server. Default: defaultPort if set, else 80.
    • protocol <string> Protocol to use. Default: 'http:'.
    • setDefaultHeaders <boolean>: Specifies whether or not to automatically add default headers such as Connection, Content-Length, Transfer-Encoding, and Host. If set to false then all necessary headers must be added manually. Defaults to true.
    • setHost <boolean>: Specifies whether or not to automatically add the Host header. If provided, this overrides setDefaultHeaders. Defaults to true.
    • signal <AbortSignal>: An AbortSignal that may be used to abort an ongoing request.
    • socketPath <string> Unix domain socket. Cannot be used if one of host or port is specified, as those specify a TCP Socket.
    • timeout <number>: A number specifying the socket timeout in milliseconds. This will set the timeout before the socket is connected.
    • uniqueHeaders <Array> A list of request headers that should be sent only once. If the header's value is an array, the items will be joined using ; .
  • callback <Function>
  • Returns: <http.ClientRequest>

options in socket.connect() are also supported.

Node.js maintains several connections per server to make HTTP requests. This function allows one to transparently issue requests.

url can be a string or a URL object. If url is a string, it is automatically parsed with new URL(). If it is a URL object, it will be automatically converted to an ordinary options object.

If both url and options are specified, the objects are merged, with the options properties taking precedence.

The optional callback parameter will be added as a one-time listener for the 'response' event.

http.request() returns an instance of the http.ClientRequest class. The ClientRequest instance is a writable stream. If one needs to upload a file with a POST request, then write to the ClientRequest object.

import http from 'node:http';
import { Buffer } from 'node:buffer';

const postData = JSON.stringify({
  'msg': 'Hello World!',
});

const options = {
  hostname: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(postData),
  },
};

const req = http.request(options, (res) => {
  console.log(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on('end', () => {
    console.log('No more data in response.');
  });
});

req.on('error', (e) => {
  console.error(`problem with request: ${e.message}`);
});

// Write data to request body
req.write(postData);
req.end();
const http = require('node:http');

const postData = JSON.stringify({
  'msg': 'Hello World!',
});

const options = {
  hostname: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(postData),
  },
};

const req = http.request(options, (res) => {
  console.log(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });
  res.on('end', () => {
    console.log('No more data in response.');
  });
});

req.on('error', (e) => {
  console.error(`problem with request: ${e.message}`);
});

// Write data to request body
req.write(postData);
req.end();
javascript

In the example req.end() was called. With http.request() one must always call req.end() to signify the end of the request - even if there is no data being written to the request body.

If any error is encountered during the request (be that with DNS resolution, TCP level errors, or actual HTTP parse errors) an 'error' event is emitted on the returned request object. As with all 'error' events, if no listeners are registered the error will be thrown.

There are a few special headers that should be noted.

  • Sending a 'Connection: keep-alive' will notify Node.js that the connection to the server should be persisted until the next request.

  • Sending a 'Content-Length' header will disable the default chunked encoding.

  • Sending an 'Expect' header will immediately send the request headers. Usually, when sending 'Expect: 100-continue', both a timeout and a listener for the 'continue' event should be set. See RFC 2616 Section 8.2.3 for more information.

  • Sending an Authorization header will override using the auth option to compute basic authentication.

Example using a URL as options:

const options = new URL('http://abc:xyz@example.com');

const req = http.request(options, (res) => {
  // ...
});
js

In a successful request, the following events will be emitted in the following order:

  • 'socket'
  • 'response'
    • 'data' any number of times, on the res object ('data' will not be emitted at all if the response body is empty, for instance, in most redirects)
    • 'end' on the res object
  • 'close'

In the case of a connection error, the following events will be emitted:

  • 'socket'
  • 'error'
  • 'close'

In the case of a premature connection close before the response is received, the following events will be emitted in the following order:

  • 'socket'
  • 'error' with an error with message 'Error: socket hang up' and code 'ECONNRESET'
  • 'close'

In the case of a premature connection close after the response is received, the following events will be emitted in the following order:

  • 'socket'
  • 'response'
    • 'data' any number of times, on the res object
  • (connection closed here)
  • 'aborted' on the res object
  • 'close'
  • 'error' on the res object with an error with message 'Error: aborted' and code 'ECONNRESET'
  • 'close' on the res object

If req.destroy() is called before a socket is assigned, the following events will be emitted in the following order:

  • (req.destroy() called here)
  • 'error' with an error with message 'Error: socket hang up' and code 'ECONNRESET', or the error with which req.destroy() was called
  • 'close'

If req.destroy() is called before the connection succeeds, the following events will be emitted in the following order:

  • 'socket'
  • (req.destroy() called here)
  • 'error' with an error with message 'Error: socket hang up' and code 'ECONNRESET', or the error with which req.destroy() was called
  • 'close'

If req.destroy() is called after the response is received, the following events will be emitted in the following order:

  • 'socket'
  • 'response'
    • 'data' any number of times, on the res object
  • (req.destroy() called here)
  • 'aborted' on the res object
  • 'close'
  • 'error' on the res object with an error with message 'Error: aborted' and code 'ECONNRESET', or the error with which req.destroy() was called
  • 'close' on the res object

If req.abort() is called before a socket is assigned, the following events will be emitted in the following order:

  • (req.abort() called here)
  • 'abort'
  • 'close'

If req.abort() is called before the connection succeeds, the following events will be emitted in the following order:

  • 'socket'
  • (req.abort() called here)
  • 'abort'
  • 'error' with an error with message 'Error: socket hang up' and code 'ECONNRESET'
  • 'close'

If req.abort() is called after the response is received, the following events will be emitted in the following order:

  • 'socket'
  • 'response'
    • 'data' any number of times, on the res object
  • (req.abort() called here)
  • 'abort'
  • 'aborted' on the res object
  • 'error' on the res object with an error with message 'Error: aborted' and code 'ECONNRESET'.
  • 'close'
  • 'close' on the res object

Setting the timeout option or using the setTimeout() function will not abort the request or do anything besides add a 'timeout' event.

Passing an AbortSignal and then calling abort() on the corresponding AbortController will behave the same way as calling .destroy() on the request. Specifically, the 'error' event will be emitted with an error with the message 'AbortError: The operation was aborted', the code 'ABORT_ERR' and the cause, if one was provided.

http.validateHeaderName(name[, label])#

  • name <string>
  • label <string> Label for error message. Default: 'Header name'.

Performs the low-level validations on the provided name that are done when res.setHeader(name, value) is called.

Passing illegal value as name will result in a TypeError being thrown, identified by code: 'ERR_INVALID_HTTP_TOKEN'.

It is not necessary to use this method before passing headers to an HTTP request or response. The HTTP module will automatically validate such headers.

Example:

import { validateHeaderName } from 'node:http';

try {
  validateHeaderName('');
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code); // --> 'ERR_INVALID_HTTP_TOKEN'
  console.error(err.message); // --> 'Header name must be a valid HTTP token [""]'
}
const { validateHeaderName } = require('node:http');

try {
  validateHeaderName('');
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code); // --> 'ERR_INVALID_HTTP_TOKEN'
  console.error(err.message); // --> 'Header name must be a valid HTTP token [""]'
}
javascript

http.validateHeaderValue(name, value)#

Performs the low-level validations on the provided value that are done when res.setHeader(name, value) is called.

Passing illegal value as value will result in a TypeError being thrown.

  • Undefined value error is identified by code: 'ERR_HTTP_INVALID_HEADER_VALUE'.
  • Invalid value character error is identified by code: 'ERR_INVALID_CHAR'.

It is not necessary to use this method before passing headers to an HTTP request or response. The HTTP module will automatically validate such headers.

Examples:

import { validateHeaderValue } from 'node:http';

try {
  validateHeaderValue('x-my-header', undefined);
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code === 'ERR_HTTP_INVALID_HEADER_VALUE'); // --> true
  console.error(err.message); // --> 'Invalid value "undefined" for header "x-my-header"'
}

try {
  validateHeaderValue('x-my-header', 'oʊmɪɡə');
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code === 'ERR_INVALID_CHAR'); // --> true
  console.error(err.message); // --> 'Invalid character in header content ["x-my-header"]'
}
const { validateHeaderValue } = require('node:http');

try {
  validateHeaderValue('x-my-header', undefined);
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code === 'ERR_HTTP_INVALID_HEADER_VALUE'); // --> true
  console.error(err.message); // --> 'Invalid value "undefined" for header "x-my-header"'
}

try {
  validateHeaderValue('x-my-header', 'oʊmɪɡə');
} catch (err) {
  console.error(err instanceof TypeError); // --> true
  console.error(err.code === 'ERR_INVALID_CHAR'); // --> true
  console.error(err.message); // --> 'Invalid character in header content ["x-my-header"]'
}
javascript

http.setMaxIdleHTTPParsers(max)#

Set the maximum number of idle HTTP parsers.

http.setGlobalProxyFromEnv([proxyEnv])#

  • proxyEnv <Object> An object containing proxy configuration. This accepts the same options as the proxyEnv option accepted by Agent. Default: process.env.
  • Returns: <Function> A function that restores the original agent and dispatcher settings to the state before this http.setGlobalProxyFromEnv() is invoked.

Dynamically resets the global configurations to enable built-in proxy support for fetch() and http.request()/https.request() at runtime, as an alternative to using the --use-env-proxy flag or NODE_USE_ENV_PROXY environment variable. It can also be used to override settings configured from the environment variables.

As this function resets the global configurations, any previously configured http.globalAgent, https.globalAgent or undici global dispatcher would be overridden after this function is invoked. It's recommended to invoke it before any requests are made and avoid invoking it in the middle of any requests.

See Built-in Proxy Support for details on proxy URL formats and NO_PROXY syntax.

Class: WebSocket#

A browser-compatible implementation of <WebSocket>.

Built-in Proxy Support#

Stability: 1.1 - Active development

When Node.js creates the global agent, if the NODE_USE_ENV_PROXY environment variable is set to 1 or --use-env-proxy is enabled, the global agent will be constructed with proxyEnv: process.env, enabling proxy support based on the environment variables.

To enable proxy support dynamically and globally, use http.setGlobalProxyFromEnv().

Custom agents can also be created with proxy support by passing a proxyEnv option when constructing the agent. The value can be process.env if they just want to inherit the configuration from the environment variables, or an object with specific setting overriding the environment.

The following properties of the proxyEnv are checked to configure proxy support.

  • HTTP_PROXY or http_proxy: Proxy server URL for HTTP requests. If both are set, http_proxy takes precedence.
  • HTTPS_PROXY or https_proxy: Proxy server URL for HTTPS requests. If both are set, https_proxy takes precedence.
  • NO_PROXY or no_proxy: Comma-separated list of hosts to bypass the proxy. If both are set, no_proxy takes precedence.

If the request is made to a Unix domain socket, the proxy settings will be ignored.

Proxy URL Format#

Proxy URLs can use either HTTP or HTTPS protocols:

  • HTTP proxy: http://proxy.example.com:8080
  • HTTPS proxy: https://proxy.example.com:8080
  • Proxy with authentication: http://username:password@proxy.example.com:8080

NO_PROXY Format#

The NO_PROXY environment variable supports several formats:

  • * - Bypass proxy for all hosts
  • example.com - Exact host name match
  • .example.com - Domain suffix match (matches sub.example.com)
  • *.example.com - Wildcard domain match
  • 192.168.1.100 - Exact IP address match
  • 192.168.1.1-192.168.1.100 - IP address range
  • example.com:8080 - Hostname with specific port

Multiple entries should be separated by commas.

Example#

To start a Node.js process with proxy support enabled for all requests sent through the default global agent, either use the NODE_USE_ENV_PROXY environment variable:

NODE_USE_ENV_PROXY=1 HTTP_PROXY=http://proxy.example.com:8080 NO_PROXY=localhost,127.0.0.1 node client.js
console

Or the --use-env-proxy flag.

HTTP_PROXY=http://proxy.example.com:8080 NO_PROXY=localhost,127.0.0.1 node --use-env-proxy client.js
console

To enable proxy support dynamically and globally with process.env (the default option of http.setGlobalProxyFromEnv()):

const http = require('node:http');

// Reads proxy-related environment variables from process.env
const restore = http.setGlobalProxyFromEnv();

// Subsequent requests will use the configured proxies from environment variables
http.get('http://www.example.com', (res) => {
  // This request will be proxied if HTTP_PROXY or http_proxy is set
});

fetch('https://www.example.com', (res) => {
  // This request will be proxied if HTTPS_PROXY or https_proxy is set
});

// To restore the original global agent and dispatcher settings, call the returned function.
// restore();
import http from 'node:http';

// Reads proxy-related environment variables from process.env
http.setGlobalProxyFromEnv();

// Subsequent requests will use the configured proxies from environment variables
http.get('http://www.example.com', (res) => {
  // This request will be proxied if HTTP_PROXY or http_proxy is set
});

fetch('https://www.example.com', (res) => {
  // This request will be proxied if HTTPS_PROXY or https_proxy is set
});

// To restore the original global agent and dispatcher settings, call the returned function.
// restore();
javascript

To enable proxy support dynamically and globally with custom settings:

const http = require('node:http');

const restore = http.setGlobalProxyFromEnv({
  http_proxy: 'http://proxy.example.com:8080',
  https_proxy: 'https://proxy.example.com:8443',
  no_proxy: 'localhost,127.0.0.1,.internal.example.com',
});

// Subsequent requests will use the configured proxies
http.get('http://www.example.com', (res) => {
  // This request will be proxied through proxy.example.com:8080
});

fetch('https://www.example.com', (res) => {
  // This request will be proxied through proxy.example.com:8443
});
import http from 'node:http';

http.setGlobalProxyFromEnv({
  http_proxy: 'http://proxy.example.com:8080',
  https_proxy: 'https://proxy.example.com:8443',
  no_proxy: 'localhost,127.0.0.1,.internal.example.com',
});

// Subsequent requests will use the configured proxies
http.get('http://www.example.com', (res) => {
  // This request will be proxied through proxy.example.com:8080
});

fetch('https://www.example.com', (res) => {
  // This request will be proxied through proxy.example.com:8443
});
javascript

To create a custom agent with built-in proxy support:

const http = require('node:http');

// Creating a custom agent with custom proxy support.
const agent = new http.Agent({ proxyEnv: { HTTP_PROXY: 'http://proxy.example.com:8080' } });

http.request({
  hostname: 'www.example.com',
  port: 80,
  path: '/',
  agent,
}, (res) => {
  // This request will be proxied through proxy.example.com:8080 using the HTTP protocol.
  console.log(`STATUS: ${res.statusCode}`);
});
cjs

Alternatively, the following also works:

const http = require('node:http');
// Use lower-cased option name.
const agent1 = new http.Agent({ proxyEnv: { http_proxy: 'http://proxy.example.com:8080' } });
// Use values inherited from the environment variables, if the process is started with
// HTTP_PROXY=http://proxy.example.com:8080 this will use the proxy server specified
// in process.env.HTTP_PROXY.
const agent2 = new http.Agent({ proxyEnv: process.env });
cjs

HTTP/2#

Stability: 2 - Stable

The node:http2 module provides an implementation of the HTTP/2 protocol. It can be accessed using:

const http2 = require('node:http2');
js

Determining if crypto support is unavailable#

It is possible for Node.js to be built without including support for the node:crypto module. In such cases, attempting to import from node:http2 or calling require('node:http2') will result in an error being thrown.

When using CommonJS, the error thrown can be caught using try/catch:

let http2;
try {
  http2 = require('node:http2');
} catch (err) {
  console.error('http2 support is disabled!');
}
cjs

When using the lexical ESM import keyword, the error can only be caught if a handler for process.on('uncaughtException') is registered before any attempt to load the module is made (using, for instance, a preload module).

When using ESM, if there is a chance that the code may be run on a build of Node.js where crypto support is not enabled, consider using the import() function instead of the lexical import keyword:

let http2;
try {
  http2 = await import('node:http2');
} catch (err) {
  console.error('http2 support is disabled!');
}
mjs

Core API#

The Core API provides a low-level interface designed specifically around support for HTTP/2 protocol features. It is specifically not designed for compatibility with the existing HTTP/1 module API. However, the Compatibility API is.

The http2 Core API is much more symmetric between client and server than the http API. For instance, most events, like 'error', 'connect' and 'stream', can be emitted either by client-side code or server-side code.

Server-side example#

The following illustrates a simple HTTP/2 server using the Core API. Since there are no browsers known that support unencrypted HTTP/2, the use of http2.createSecureServer() is necessary when communicating with browser clients.

import { createSecureServer } from 'node:http2';
import { readFileSync } from 'node:fs';

const server = createSecureServer({
  key: readFileSync('localhost-privkey.pem'),
  cert: readFileSync('localhost-cert.pem'),
});

server.on('error', (err) => console.error(err));

server.on('stream', (stream, headers) => {
  // stream is a Duplex
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8443);
const http2 = require('node:http2');
const fs = require('node:fs');

const server = http2.createSecureServer({
  key: fs.readFileSync('localhost-privkey.pem'),
  cert: fs.readFileSync('localhost-cert.pem'),
});
server.on('error', (err) => console.error(err));

server.on('stream', (stream, headers) => {
  // stream is a Duplex
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8443);
javascript

To generate the certificate and key for this example, run:

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
  -keyout localhost-privkey.pem -out localhost-cert.pem
bash

Client-side example#

The following illustrates an HTTP/2 client:

import { connect } from 'node:http2';
import { readFileSync } from 'node:fs';

const client = connect('https://localhost:8443', {
  ca: readFileSync('localhost-cert.pem'),
});
client.on('error', (err) => console.error(err));

const req = client.request({ ':path': '/' });

req.on('response', (headers, flags) => {
  for (const name in headers) {
    console.log(`${name}: ${headers[name]}`);
  }
});

req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
  console.log(`\n${data}`);
  client.close();
});
req.end();
const http2 = require('node:http2');
const fs = require('node:fs');

const client = http2.connect('https://localhost:8443', {
  ca: fs.readFileSync('localhost-cert.pem'),
});
client.on('error', (err) => console.error(err));

const req = client.request({ ':path': '/' });

req.on('response', (headers, flags) => {
  for (const name in headers) {
    console.log(`${name}: ${headers[name]}`);
  }
});

req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
  console.log(`\n${data}`);
  client.close();
});
req.end();
javascript

Class: Http2Session#

Instances of the http2.Http2Session class represent an active communications session between an HTTP/2 client and server. Instances of this class are not intended to be constructed directly by user code.

Each Http2Session instance will exhibit slightly different behaviors depending on whether it is operating as a server or a client. The http2session.type property can be used to determine the mode in which an Http2Session is operating. On the server side, user code should rarely have occasion to work with the Http2Session object directly, with most actions typically taken through interactions with either the Http2Server or Http2Stream objects.

User code will not create Http2Session instances directly. Server-side Http2Session instances are created by the Http2Server instance when a new HTTP/2 connection is received. Client-side Http2Session instances are created using the http2.connect() method.

Http2Session and sockets#

Every Http2Session instance is associated with exactly one net.Socket or tls.TLSSocket when it is created. When either the Socket or the Http2Session are destroyed, both will be destroyed.

Because of the specific serialization and processing requirements imposed by the HTTP/2 protocol, it is not recommended for user code to read data from or write data to a Socket instance bound to a Http2Session. Doing so can put the HTTP/2 session into an indeterminate state causing the session and the socket to become unusable.

Once a Socket has been bound to an Http2Session, user code should rely solely on the API of the Http2Session.

Event: 'close'#

The 'close' event is emitted once the Http2Session has been destroyed. Its listener does not expect any arguments.

Event: 'connect'#

The 'connect' event is emitted once the Http2Session has been successfully connected to the remote peer and communication may begin.

User code will typically not listen for this event directly.

Event: 'error'#

The 'error' event is emitted when an error occurs during the processing of an Http2Session.

Event: 'frameError'#
  • type <integer> The frame type.
  • code <integer> The error code.
  • id <integer> The stream id (or 0 if the frame isn't associated with a stream).

The 'frameError' event is emitted when an error occurs while attempting to send a frame on the session. If the frame that could not be sent is associated with a specific Http2Stream, an attempt to emit a 'frameError' event on the Http2Stream is made.

If the 'frameError' event is associated with a stream, the stream will be closed and destroyed immediately following the 'frameError' event. If the event is not associated with a stream, the Http2Session will be shut down immediately following the 'frameError' event.

Event: 'goaway'#
  • errorCode <number> The HTTP/2 error code specified in the GOAWAY frame.
  • lastStreamID <number> The ID of the last stream the remote peer successfully processed (or 0 if no ID is specified).
  • opaqueData <Buffer> If additional opaque data was included in the GOAWAY frame, a Buffer instance will be passed containing that data.

The 'goaway' event is emitted when a GOAWAY frame is received.

The Http2Session instance will be shut down automatically when the 'goaway' event is emitted.

Event: 'localSettings'#

The 'localSettings' event is emitted when an acknowledgment SETTINGS frame has been received.

When using http2session.settings() to submit new settings, the modified settings do not take effect until the 'localSettings' event is emitted.

session.settings({ enablePush: false });

session.on('localSettings', (settings) => {
  /* Use the new settings */
});
js
Event: 'ping'#
  • payload <Buffer> The PING frame 8-byte payload

The 'ping' event is emitted whenever a PING frame is received from the connected peer.

Event: 'remoteSettings'#

The 'remoteSettings' event is emitted when a new SETTINGS frame is received from the connected peer.

session.on('remoteSettings', (settings) => {
  /* Use the new settings */
});
js
Event: 'stream'#
  • stream <Http2Stream> A reference to the stream
  • headers <HTTP/2 Headers Object> An object describing the headers
  • flags <number> The associated numeric flags
  • rawHeaders {HTTP/2 Raw Headers} An array containing the raw headers

The 'stream' event is emitted when a new Http2Stream is created.

session.on('stream', (stream, headers, flags) => {
  const method = headers[':method'];
  const path = headers[':path'];
  // ...
  stream.respond({
    ':status': 200,
    'content-type': 'text/plain; charset=utf-8',
  });
  stream.write('hello ');
  stream.end('world');
});
js

On the server side, user code will typically not listen for this event directly, and would instead register a handler for the 'stream' event emitted by the net.Server or tls.Server instances returned by http2.createServer() and http2.createSecureServer(), respectively, as in the example below:

import { createServer } from 'node:http2';

// Create an unencrypted HTTP/2 server
const server = createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.on('error', (error) => console.error(error));
  stream.end('<h1>Hello World</h1>');
});

server.listen(8000);
const http2 = require('node:http2');

// Create an unencrypted HTTP/2 server
const server = http2.createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.on('error', (error) => console.error(error));
  stream.end('<h1>Hello World</h1>');
});

server.listen(8000);
javascript

Even though HTTP/2 streams and network sockets are not in a 1:1 correspondence, a network error will destroy each individual stream and must be handled on the stream level, as shown above.

Event: 'timeout'#

After the http2session.setTimeout() method is used to set the timeout period for this Http2Session, the 'timeout' event is emitted if there is no activity on the Http2Session after the configured number of milliseconds. Its listener does not expect any arguments.

session.setTimeout(2000);
session.on('timeout', () => { /* .. */ });
js
http2session.alpnProtocol#

Value will be undefined if the Http2Session is not yet connected to a socket, h2c if the Http2Session is not connected to a TLSSocket, or will return the value of the connected TLSSocket's own alpnProtocol property.

http2session.close([callback])#

Gracefully closes the Http2Session, allowing any existing streams to complete on their own and preventing new Http2Stream instances from being created. Once closed, http2session.destroy() might be called if there are no open Http2Stream instances.

If specified, the callback function is registered as a handler for the 'close' event.

http2session.closed#

Will be true if this Http2Session instance has been closed, otherwise false.

http2session.connecting#

Will be true if this Http2Session instance is still connecting, will be set to false before emitting connect event and/or calling the http2.connect callback.

http2session.destroy([error][, code])#
  • error <Error> An Error object if the Http2Session is being destroyed due to an error.
  • code <number> The HTTP/2 error code to send in the final GOAWAY frame. If unspecified, and error is not undefined, the default is INTERNAL_ERROR, otherwise defaults to NO_ERROR.

Immediately terminates the Http2Session and the associated net.Socket or tls.TLSSocket.

Once destroyed, the Http2Session will emit the 'close' event. If error is not undefined, an 'error' event will be emitted immediately before the 'close' event.

If there are any remaining open Http2Streams associated with the Http2Session, those will also be destroyed.

http2session.destroyed#

Will be true if this Http2Session instance has been destroyed and must no longer be used, otherwise false.

http2session.encrypted#

Value is undefined if the Http2Session session socket has not yet been connected, true if the Http2Session is connected with a TLSSocket, and false if the Http2Session is connected to any other kind of socket or stream.

http2session.goaway([code[, lastStreamID[, opaqueData]]])#
  • code <number> An HTTP/2 error code
  • lastStreamID <number> The numeric ID of the last processed Http2Stream
  • opaqueData <Buffer> | <TypedArray> | <DataView>TypedArray or DataView instance containing additional data to be carried within the GOAWAY frame.

Transmits a GOAWAY frame to the connected peer without shutting down the Http2Session.

http2session.localSettings#

A prototype-less object describing the current local settings of this Http2Session. The local settings are local to this Http2Session instance.

http2session.originSet#

If the Http2Session is connected to a TLSSocket, the originSet property will return an Array of origins for which the Http2Session may be considered authoritative.

The originSet property is only available when using a secure TLS connection.

http2session.pendingSettingsAck#

Indicates whether the Http2Session is currently waiting for acknowledgment of a sent SETTINGS frame. Will be true after calling the http2session.settings() method. Will be false once all sent SETTINGS frames have been acknowledged.

http2session.ping([payload, ]callback)#

Sends a PING frame to the connected HTTP/2 peer. A callback function must be provided. The method will return true if the PING was sent, false otherwise.

The maximum number of outstanding (unacknowledged) pings is determined by the maxOutstandingPings configuration option. The default maximum is 10.

If provided, the payload must be a Buffer, TypedArray, or DataView containing 8 bytes of data that will be transmitted with the PING and returned with the ping acknowledgment.

The callback will be invoked with three arguments: an error argument that will be null if the PING was successfully acknowledged, a duration argument that reports the number of milliseconds elapsed since the ping was sent and the acknowledgment was received, and a Buffer containing the 8-byte PING payload.

session.ping(Buffer.from('abcdefgh'), (err, duration, payload) => {
  if (!err) {
    console.log(`Ping acknowledged in ${duration} milliseconds`);
    console.log(`With payload '${payload.toString()}'`);
  }
});
js

If the payload argument is not specified, the default payload will be the 64-bit timestamp (little endian) marking the start of the PING duration.

http2session.ref()#

Calls ref() on this Http2Session instance's underlying net.Socket.

http2session.remoteSettings#

A prototype-less object describing the current remote settings of this Http2Session. The remote settings are set by the connected HTTP/2 peer.

http2session.setLocalWindowSize(windowSize)#

Sets the local endpoint's window size. The windowSize is the total window size to set, not the delta.

import { createServer } from 'node:http2';

const server = createServer();
const expectedWindowSize = 2 ** 20;
server.on('session', (session) => {

  // Set local window size to be 2 ** 20
  session.setLocalWindowSize(expectedWindowSize);
});
const http2 = require('node:http2');

const server = http2.createServer();
const expectedWindowSize = 2 ** 20;
server.on('session', (session) => {

  // Set local window size to be 2 ** 20
  session.setLocalWindowSize(expectedWindowSize);
});
javascript

For http2 clients the proper event is either 'connect' or 'remoteSettings'.

http2session.setTimeout(msecs, callback)#

Used to set a callback function that is called when there is no activity on the Http2Session after msecs milliseconds. The given callback is registered as a listener on the 'timeout' event.

http2session.socket#

Returns a Proxy object that acts as a net.Socket (or tls.TLSSocket) but limits available methods to ones safe to use with HTTP/2.

destroy, emit, end, pause, read, resume, and write will throw an error with code ERR_HTTP2_NO_SOCKET_MANIPULATION. See Http2Session and Sockets for more information.

setTimeout method will be called on this Http2Session.

All other interactions will be routed directly to the socket.

http2session.state#

Provides miscellaneous information about the current state of the Http2Session.

  • Type: <Object>
    • effectiveLocalWindowSize <number> The current local (receive) flow control window size for the Http2Session.
    • effectiveRecvDataLength <number> The current number of bytes that have been received since the last flow control WINDOW_UPDATE.
    • nextStreamID <number> The numeric identifier to be used the next time a new Http2Stream is created by this Http2Session.
    • localWindowSize <number> The number of bytes that the remote peer can send without receiving a WINDOW_UPDATE.
    • lastProcStreamID <number> The numeric id of the Http2Stream for which a HEADERS or DATA frame was most recently received.
    • remoteWindowSize <number> The number of bytes that this Http2Session may send without receiving a WINDOW_UPDATE.
    • outboundQueueSize <number> The number of frames currently within the outbound queue for this Http2Session.
    • deflateDynamicTableSize <number> The current size in bytes of the outbound header compression state table.
    • inflateDynamicTableSize <number> The current size in bytes of the inbound header compression state table.

An object describing the current status of this Http2Session.

http2session.settings([settings][, callback])#

Updates the current local settings for this Http2Session and sends a new SETTINGS frame to the connected HTTP/2 peer.

Once called, the http2session.pendingSettingsAck property will be true while the session is waiting for the remote peer to acknowledge the new settings.

The new settings will not become effective until the SETTINGS acknowledgment is received and the 'localSettings' event is emitted. It is possible to send multiple SETTINGS frames while acknowledgment is still pending.

http2session.type#

The http2session.type will be equal to http2.constants.NGHTTP2_SESSION_SERVER if this Http2Session instance is a server, and http2.constants.NGHTTP2_SESSION_CLIENT if the instance is a client.

http2session.unref()#

Calls unref() on this Http2Session instance's underlying net.Socket.

Class: ServerHttp2Session#

serverhttp2session.altsvc(alt, originOrStream)#
  • alt <string> A description of the alternative service configuration as defined by RFC 7838.
  • originOrStream <number> | <string> | <URL> | <Object> Either a URL string specifying the origin (or an Object with an origin property) or the numeric identifier of an active Http2Stream as given by the http2stream.id property.

Submits an ALTSVC frame (as defined by RFC 7838) to the connected client.

import { createServer } from 'node:http2';

const server = createServer();
server.on('session', (session) => {
  // Set altsvc for origin https://example.org:80
  session.altsvc('h2=":8000"', 'https://example.org:80');
});

server.on('stream', (stream) => {
  // Set altsvc for a specific stream
  stream.session.altsvc('h2=":8000"', stream.id);
});
const http2 = require('node:http2');

const server = http2.createServer();
server.on('session', (session) => {
  // Set altsvc for origin https://example.org:80
  session.altsvc('h2=":8000"', 'https://example.org:80');
});

server.on('stream', (stream) => {
  // Set altsvc for a specific stream
  stream.session.altsvc('h2=":8000"', stream.id);
});
javascript

Sending an ALTSVC frame with a specific stream ID indicates that the alternate service is associated with the origin of the given Http2Stream.

The alt and origin string must contain only ASCII bytes and are strictly interpreted as a sequence of ASCII bytes. The special value 'clear' may be passed to clear any previously set alternative service for a given domain.

When a string is passed for the originOrStream argument, it will be parsed as a URL and the origin will be derived. For instance, the origin for the HTTP URL 'https://example.org/foo/bar' is the ASCII string 'https://example.org'. An error will be thrown if either the given string cannot be parsed as a URL or if a valid origin cannot be derived.

A URL object, or any object with an origin property, may be passed as originOrStream, in which case the value of the origin property will be used. The value of the origin property must be a properly serialized ASCII origin.

Specifying alternative services#

The format of the alt parameter is strictly defined by RFC 7838 as an ASCII string containing a comma-delimited list of "alternative" protocols associated with a specific host and port.

For example, the value 'h2="example.org:81"' indicates that the HTTP/2 protocol is available on the host 'example.org' on TCP/IP port 81. The host and port must be contained within the quote (") characters.

Multiple alternatives may be specified, for instance: 'h2="example.org:81", h2=":82"'.

The protocol identifier ('h2' in the examples) may be any valid ALPN Protocol ID.

The syntax of these values is not validated by the Node.js implementation and are passed through as provided by the user or received from the peer.

serverhttp2session.origin(...origins)#
  • origins { string | URL | Object } One or more URL Strings passed as separate arguments.

Submits an ORIGIN frame (as defined by RFC 8336) to the connected client to advertise the set of origins for which the server is capable of providing authoritative responses.

import { createSecureServer } from 'node:http2';
const options = getSecureOptionsSomehow();
const server = createSecureServer(options);
server.on('stream', (stream) => {
  stream.respond();
  stream.end('ok');
});
server.on('session', (session) => {
  session.origin('https://example.com', 'https://example.org');
});
const http2 = require('node:http2');
const options = getSecureOptionsSomehow();
const server = http2.createSecureServer(options);
server.on('stream', (stream) => {
  stream.respond();
  stream.end('ok');
});
server.on('session', (session) => {
  session.origin('https://example.com', 'https://example.org');
});
javascript

When a string is passed as an origin, it will be parsed as a URL and the origin will be derived. For instance, the origin for the HTTP URL 'https://example.org/foo/bar' is the ASCII string 'https://example.org'. An error will be thrown if either the given string cannot be parsed as a URL or if a valid origin cannot be derived.

A URL object, or any object with an origin property, may be passed as an origin, in which case the value of the origin property will be used. The value of the origin property must be a properly serialized ASCII origin.

Alternatively, the origins option may be used when creating a new HTTP/2 server using the http2.createSecureServer() method:

import { createSecureServer } from 'node:http2';
const options = getSecureOptionsSomehow();
options.origins = ['https://example.com', 'https://example.org'];
const server = createSecureServer(options);
server.on('stream', (stream) => {
  stream.respond();
  stream.end('ok');
});
const http2 = require('node:http2');
const options = getSecureOptionsSomehow();
options.origins = ['https://example.com', 'https://example.org'];
const server = http2.createSecureServer(options);
server.on('stream', (stream) => {
  stream.respond();
  stream.end('ok');
});
javascript

Class: ClientHttp2Session#

Event: 'altsvc'#

The 'altsvc' event is emitted whenever an ALTSVC frame is received by the client. The event is emitted with the ALTSVC value, origin, and stream ID. If no origin is provided in the ALTSVC frame, origin will be an empty string.

import { connect } from 'node:http2';
const client = connect('https://example.org');

client.on('altsvc', (alt, origin, streamId) => {
  console.log(alt);
  console.log(origin);
  console.log(streamId);
});
const http2 = require('node:http2');
const client = http2.connect('https://example.org');

client.on('altsvc', (alt, origin, streamId) => {
  console.log(alt);
  console.log(origin);
  console.log(streamId);
});
javascript
Event: 'origin'#

The 'origin' event is emitted whenever an ORIGIN frame is received by the client. The event is emitted with an array of origin strings. The http2session.originSet will be updated to include the received origins.

import { connect } from 'node:http2';
const client = connect('https://example.org');

client.on('origin', (origins) => {
  for (let n = 0; n < origins.length; n++)
    console.log(origins[n]);
});
const http2 = require('node:http2');
const client = http2.connect('https://example.org');

client.on('origin', (origins) => {
  for (let n = 0; n < origins.length; n++)
    console.log(origins[n]);
});
javascript

The 'origin' event is only emitted when using a secure TLS connection.

clienthttp2session.request(headers[, options])#
  • headers <HTTP/2 Headers Object> | <HTTP/2 Raw Headers>

  • options <Object>

    • endStream <boolean> true if the Http2Stream writable side should be closed initially, such as when sending a GET request that should not expect a payload body.
    • exclusive <boolean> When true and parent identifies a parent Stream, the created stream is made the sole direct dependency of the parent, with all other existing dependents made a dependent of the newly created stream. Default: false.
    • parent <number> Specifies the numeric identifier of a stream the newly created stream is dependent on.
    • waitForTrailers <boolean> When true, the Http2Stream will emit the 'wantTrailers' event after the final DATA frame has been sent.
    • signal <AbortSignal> An AbortSignal that may be used to abort an ongoing request.
  • Returns: <ClientHttp2Stream>

For HTTP/2 Client Http2Session instances only, the http2session.request() creates and returns an Http2Stream instance that can be used to send an HTTP/2 request to the connected server.

When a ClientHttp2Session is first created, the socket may not yet be connected. If clienthttp2session.request() is called during this time, the actual request will be deferred until the socket is ready to go.

If the session becomes unavailable before the request can be created, the returned stream will emit ERR_HTTP2_GOAWAY_SESSION or ERR_HTTP2_INVALID_SESSION asynchronously.

This method is only available if http2session.type is equal to http2.constants.NGHTTP2_SESSION_CLIENT.

import { connect, constants } from 'node:http2';
const clientSession = connect('https://localhost:1234');
const {
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
} = constants;

const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('response', (headers) => {
  console.log(headers[HTTP2_HEADER_STATUS]);
  req.on('data', (chunk) => { /* .. */ });
  req.on('end', () => { /* .. */ });
});
const http2 = require('node:http2');
const clientSession = http2.connect('https://localhost:1234');
const {
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
} = http2.constants;

const req = clientSession.request({ [HTTP2_HEADER_PATH]: '/' });
req.on('response', (headers) => {
  console.log(headers[HTTP2_HEADER_STATUS]);
  req.on('data', (chunk) => { /* .. */ });
  req.on('end', () => { /* .. */ });
});
javascript

When the options.waitForTrailers option is set, the 'wantTrailers' event is emitted immediately after queuing the last chunk of payload data to be sent. The http2stream.sendTrailers() method can then be called to send trailing headers to the peer.

When options.waitForTrailers is set, the Http2Stream will not automatically close when the final DATA frame is transmitted. User code must call either http2stream.sendTrailers() or http2stream.close() to close the Http2Stream.

When options.signal is set with an AbortSignal and then abort on the corresponding AbortController is called, the request will emit an 'error' event with an AbortError error.

The :method and :path pseudo-headers are not specified within headers, they respectively default to:

  • :method = 'GET'
  • :path = /

Class: Http2Stream#

Each instance of the Http2Stream class represents a bidirectional HTTP/2 communications stream over an Http2Session instance. Any single Http2Session may have up to 231-1 Http2Stream instances over its lifetime.

User code will not construct Http2Stream instances directly. Rather, these are created, managed, and provided to user code through the Http2Session instance. On the server, Http2Stream instances are created either in response to an incoming HTTP request (and handed off to user code via the 'stream' event), or in response to a call to the http2stream.pushStream() method. On the client, Http2Stream instances are created and returned when either the http2session.request() method is called, or in response to an incoming 'push' event.

The Http2Stream class is a base for the ServerHttp2Stream and ClientHttp2Stream classes, each of which is used specifically by either the Server or Client side, respectively.

All Http2Stream instances are Duplex streams. The Writable side of the Duplex is used to send data to the connected peer, while the Readable side is used to receive data sent by the connected peer.

The default text character encoding for an Http2Stream is UTF-8. When using an Http2Stream to send text, use the 'content-type' header to set the character encoding.

stream.respond({
  'content-type': 'text/html; charset=utf-8',
  ':status': 200,
});
js
Http2Stream Lifecycle#
Creation#

On the server side, instances of ServerHttp2Stream are created either when:

  • A new HTTP/2 HEADERS frame with a previously unused stream ID is received;
  • The http2stream.pushStream() method is called.

On the client side, instances of ClientHttp2Stream are created when the http2session.request() method is called.

On the client, the Http2Stream instance returned by http2session.request() may not be immediately ready for use if the parent Http2Session has not yet been fully established. In such cases, operations called on the Http2Stream will be buffered until the 'ready' event is emitted. User code should rarely, if ever, need to handle the 'ready' event directly. The ready status of an Http2Stream can be determined by checking the value of http2stream.id. If the value is undefined, the stream is not yet ready for use.

Destruction#

All Http2Stream instances are destroyed either when:

  • An RST_STREAM frame for the stream is received by the connected peer, and (for client streams only) pending data has been read.
  • The http2stream.close() method is called, and (for client streams only) pending data has been read.
  • The http2stream.destroy() or http2session.destroy() methods are called.

When an Http2Stream instance is destroyed, an attempt will be made to send an RST_STREAM frame to the connected peer.

When the Http2Stream instance is destroyed, the 'close' event will be emitted. Because Http2Stream is an instance of stream.Duplex, the 'end' event will also be emitted if the stream data is currently flowing. The 'error' event may also be emitted if http2stream.destroy() was called with an Error passed as the first argument.

After the Http2Stream has been destroyed, the http2stream.destroyed property will be true and the http2stream.rstCode property will specify the RST_STREAM error code. The Http2Stream instance is no longer usable once destroyed.

Event: 'aborted'#

The 'aborted' event is emitted whenever a Http2Stream instance is abnormally aborted in mid-communication. Its listener does not expect any arguments.

The 'aborted' event will only be emitted if the Http2Stream writable side has not been ended.

Event: 'close'#

The 'close' event is emitted when the Http2Stream is destroyed. Once this event is emitted, the Http2Stream instance is no longer usable.

The HTTP/2 error code used when closing the stream can be retrieved using the http2stream.rstCode property. If the code is any value other than NGHTTP2_NO_ERROR (0), an 'error' event will have also been emitted.

Event: 'error'#

The 'error' event is emitted when an error occurs during the processing of an Http2Stream.

Event: 'frameError'#
  • type <integer> The frame type.
  • code <integer> The error code.
  • id <integer> The stream id (or 0 if the frame isn't associated with a stream).

The 'frameError' event is emitted when an error occurs while attempting to send a frame. When invoked, the handler function will receive an integer argument identifying the frame type, and an integer argument identifying the error code. The Http2Stream instance will be destroyed immediately after the 'frameError' event is emitted.

Event: 'ready'#

The 'ready' event is emitted when the Http2Stream has been opened, has been assigned an id, and can be used. The listener does not expect any arguments.

Event: 'timeout'#

The 'timeout' event is emitted after no activity is received for this Http2Stream within the number of milliseconds set using http2stream.setTimeout(). Its listener does not expect any arguments.

Event: 'trailers'#

The 'trailers' event is emitted when a block of headers associated with trailing header fields is received. The listener callback is passed the HTTP/2 Headers Object, flags associated with the headers, and the headers in raw format (see HTTP/2 Raw Headers).

This event might not be emitted if http2stream.end() is called before trailers are received and the incoming data is not being read or listened for.

stream.on('trailers', (headers, flags) => {
  console.log(headers);
});
js
Event: 'wantTrailers'#

The 'wantTrailers' event is emitted when the Http2Stream has queued the final DATA frame to be sent on a frame and the Http2Stream is ready to send trailing headers. When initiating a request or response, the waitForTrailers option must be set for this event to be emitted.

http2stream.aborted#

Set to true if the Http2Stream instance was aborted abnormally. When set, the 'aborted' event will have been emitted.

http2stream.bufferSize#

This property shows the number of characters currently buffered to be written. See net.Socket.bufferSize for details.

http2stream.close(code[, callback])#
  • code <number> Unsigned 32-bit integer identifying the error code. Default: http2.constants.NGHTTP2_NO_ERROR (0x00).
  • callback <Function> An optional function registered to listen for the 'close' event.

Closes the Http2Stream instance by sending an RST_STREAM frame to the connected HTTP/2 peer.

http2stream.closed#

Set to true if the Http2Stream instance has been closed.

http2stream.destroyed#

Set to true if the Http2Stream instance has been destroyed and is no longer usable.

http2stream.endAfterHeaders#

Set to true if the END_STREAM flag was set in the request or response HEADERS frame received, indicating that no additional data should be received and the readable side of the Http2Stream will be closed.

http2stream.id#

The numeric stream identifier of this Http2Stream instance. Set to undefined if the stream identifier has not yet been assigned.

http2stream.pending#

Set to true if the Http2Stream instance has not yet been assigned a numeric stream identifier.

http2stream.priority(options)#

Stability: 0 - Deprecated: support for priority signaling has been deprecated in the RFC 9113 and is no longer supported in Node.js.

Empty method, only there to maintain some backward compatibility.

http2stream.rstCode#

Set to the RST_STREAM error code reported when the Http2Stream is destroyed after either receiving an RST_STREAM frame from the connected peer, calling http2stream.close(), or http2stream.destroy(). Will be undefined if the Http2Stream has not been closed.

http2stream.sentHeaders#

An object containing the outbound headers sent for this Http2Stream.

http2stream.sentInfoHeaders#

An array of objects containing the outbound informational (additional) headers sent for this Http2Stream.

http2stream.sentTrailers#

An object containing the outbound trailers sent for this HttpStream.

http2stream.session#

A reference to the Http2Session instance that owns this Http2Stream. The value will be undefined after the Http2Stream instance is destroyed.

http2stream.setTimeout(msecs, callback)#
import { connect, constants } from 'node:http2';
const client = connect('http://example.org:8000');
const { NGHTTP2_CANCEL } = constants;
const req = client.request({ ':path': '/' });

// Cancel the stream if there's no activity after 5 seconds
req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL));
const http2 = require('node:http2');
const client = http2.connect('http://example.org:8000');
const { NGHTTP2_CANCEL } = http2.constants;
const req = client.request({ ':path': '/' });

// Cancel the stream if there's no activity after 5 seconds
req.setTimeout(5000, () => req.close(NGHTTP2_CANCEL));
javascript
http2stream.state#

Provides miscellaneous information about the current state of the Http2Stream.

  • Type: <Object>
    • localWindowSize <number> The number of bytes the connected peer may send for this Http2Stream without receiving a WINDOW_UPDATE.
    • state <number> A flag indicating the low-level current state of the Http2Stream as determined by nghttp2.
    • localClose <number> 1 if this Http2Stream has been closed locally.
    • remoteClose <number> 1 if this Http2Stream has been closed remotely.
    • sumDependencyWeight <number> Legacy property, always set to 0.
    • weight <number> Legacy property, always set to 16.

A current state of this Http2Stream.

http2stream.sendTrailers(headers)#

Sends a trailing HEADERS frame to the connected HTTP/2 peer. This method will cause the Http2Stream to be immediately closed and must only be called after the 'wantTrailers' event has been emitted. When sending a request or sending a response, the options.waitForTrailers option must be set in order to keep the Http2Stream open after the final DATA frame so that trailers can be sent.

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  stream.respond(undefined, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ xyz: 'abc' });
  });
  stream.end('Hello World');
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond(undefined, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ xyz: 'abc' });
  });
  stream.end('Hello World');
});
javascript

The HTTP/1 specification forbids trailers from containing HTTP/2 pseudo-header fields (e.g. ':method', ':path', etc).

Class: ClientHttp2Stream#

The ClientHttp2Stream class is an extension of Http2Stream that is used exclusively on HTTP/2 Clients. Http2Stream instances on the client provide events such as 'response' and 'push' that are only relevant on the client.

Event: 'continue'#

Emitted when the server sends a 100 Continue status, usually because the request contained Expect: 100-continue. This is an instruction that the client should send the request body.

Event: 'headers'#

The 'headers' event is emitted when an additional block of headers is received for a stream, such as when a block of 1xx informational headers is received. The listener callback is passed the HTTP/2 Headers Object, flags associated with the headers, and the headers in raw format (see HTTP/2 Raw Headers).

stream.on('headers', (headers, flags) => {
  console.log(headers);
});
js
Event: 'push'#

The 'push' event is emitted when response headers for a Server Push stream are received. The listener callback is passed the HTTP/2 Headers Object, flags associated with the headers, and the headers in raw format (see HTTP/2 Raw Headers).

stream.on('push', (headers, flags) => {
  console.log(headers);
});
js
Event: 'response'#

The 'response' event is emitted when a response HEADERS frame has been received for this stream from the connected HTTP/2 server. The listener is invoked with three arguments: an Object containing the received HTTP/2 Headers Object, flags associated with the headers, and the headers in raw format (see HTTP/2 Raw Headers).

import { connect } from 'node:http2';
const client = connect('https://localhost');
const req = client.request({ ':path': '/' });
req.on('response', (headers, flags) => {
  console.log(headers[':status']);
});
const http2 = require('node:http2');
const client = http2.connect('https://localhost');
const req = client.request({ ':path': '/' });
req.on('response', (headers, flags) => {
  console.log(headers[':status']);
});
javascript

Class: ServerHttp2Stream#

The ServerHttp2Stream class is an extension of Http2Stream that is used exclusively on HTTP/2 Servers. Http2Stream instances on the server provide additional methods such as http2stream.pushStream() and http2stream.respond() that are only relevant on the server.

http2stream.additionalHeaders(headers)#

Sends an additional informational HEADERS frame to the connected HTTP/2 peer.

http2stream.headersSent#

True if headers were sent, false otherwise (read-only).

http2stream.pushAllowed#

Read-only property mapped to the SETTINGS_ENABLE_PUSH flag of the remote client's most recent SETTINGS frame. Will be true if the remote peer accepts push streams, false otherwise. Settings are the same for every Http2Stream in the same Http2Session.

http2stream.pushStream(headers[, options], callback)#
  • headers <HTTP/2 Headers Object>
  • options <Object>
    • exclusive <boolean> When true and parent identifies a parent Stream, the created stream is made the sole direct dependency of the parent, with all other existing dependents made a dependent of the newly created stream. Default: false.
    • parent <number> Specifies the numeric identifier of a stream the newly created stream is dependent on.
  • callback <Function> Callback that is called once the push stream has been initiated.

Initiates a push stream. The callback is invoked with the new Http2Stream instance created for the push stream passed as the second argument, or an Error passed as the first argument.

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.pushStream({ ':path': '/' }, (err, pushStream, headers) => {
    if (err) throw err;
    pushStream.respond({ ':status': 200 });
    pushStream.end('some pushed data');
  });
  stream.end('some data');
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.pushStream({ ':path': '/' }, (err, pushStream, headers) => {
    if (err) throw err;
    pushStream.respond({ ':status': 200 });
    pushStream.end('some pushed data');
  });
  stream.end('some data');
});
javascript

Setting the weight of a push stream is not allowed in the HEADERS frame. Pass a weight value to http2stream.priority with the silent option set to true to enable server-side bandwidth balancing between concurrent streams.

Calling http2stream.pushStream() from within a pushed stream is not permitted and will throw an error.

http2stream.respond([headers[, options]])#
  • headers <HTTP/2 Headers Object> | <HTTP/2 Raw Headers>
  • options <Object>
    • endStream <boolean> Set to true to indicate that the response will not include payload data.
    • waitForTrailers <boolean> When true, the Http2Stream will emit the 'wantTrailers' event after the final DATA frame has been sent.
import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.end('some data');
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 });
  stream.end('some data');
});
javascript

Initiates a response. When the options.waitForTrailers option is set, the 'wantTrailers' event will be emitted immediately after queuing the last chunk of payload data to be sent. The http2stream.sendTrailers() method can then be used to send trailing header fields to the peer.

When options.waitForTrailers is set, the Http2Stream will not automatically close when the final DATA frame is transmitted. User code must call either http2stream.sendTrailers() or http2stream.close() to close the Http2Stream.

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 }, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });
  stream.end('some data');
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respond({ ':status': 200 }, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });
  stream.end('some data');
});
javascript
http2stream.respondWithFD(fd[, headers[, options]])#

Initiates a response whose data is read from the given file descriptor. No validation is performed on the given file descriptor. If an error occurs while attempting to read data using the file descriptor, the Http2Stream will be closed using an RST_STREAM frame using the standard INTERNAL_ERROR code.

When used, the Http2Stream object's Duplex interface will be closed automatically.

import { createServer } from 'node:http2';
import { openSync, fstatSync, closeSync } from 'node:fs';

const server = createServer();
server.on('stream', (stream) => {
  const fd = openSync('/some/file', 'r');

  const stat = fstatSync(fd);
  const headers = {
    'content-length': stat.size,
    'last-modified': stat.mtime.toUTCString(),
    'content-type': 'text/plain; charset=utf-8',
  };
  stream.respondWithFD(fd, headers);
  stream.on('close', () => closeSync(fd));
});
const http2 = require('node:http2');
const fs = require('node:fs');

const server = http2.createServer();
server.on('stream', (stream) => {
  const fd = fs.openSync('/some/file', 'r');

  const stat = fs.fstatSync(fd);
  const headers = {
    'content-length': stat.size,
    'last-modified': stat.mtime.toUTCString(),
    'content-type': 'text/plain; charset=utf-8',
  };
  stream.respondWithFD(fd, headers);
  stream.on('close', () => fs.closeSync(fd));
});
javascript

The optional options.statCheck function may be specified to give user code an opportunity to set additional content headers based on the fs.Stat details of the given fd. If the statCheck function is provided, the http2stream.respondWithFD() method will perform an fs.fstat() call to collect details on the provided file descriptor.

The offset and length options may be used to limit the response to a specific range subset. This can be used, for instance, to support HTTP Range requests.

The file descriptor or FileHandle is not closed when the stream is closed, so it will need to be closed manually once it is no longer needed. Using the same file descriptor concurrently for multiple streams is not supported and may result in data loss. Re-using a file descriptor after a stream has finished is supported.

When the options.waitForTrailers option is set, the 'wantTrailers' event will be emitted immediately after queuing the last chunk of payload data to be sent. The http2stream.sendTrailers() method can then be used to send trailing header fields to the peer.

When options.waitForTrailers is set, the Http2Stream will not automatically close when the final DATA frame is transmitted. User code must call either http2stream.sendTrailers() or http2stream.close() to close the Http2Stream.

import { createServer } from 'node:http2';
import { openSync, fstatSync, closeSync } from 'node:fs';

const server = createServer();
server.on('stream', (stream) => {
  const fd = openSync('/some/file', 'r');

  const stat = fstatSync(fd);
  const headers = {
    'content-length': stat.size,
    'last-modified': stat.mtime.toUTCString(),
    'content-type': 'text/plain; charset=utf-8',
  };
  stream.respondWithFD(fd, headers, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });

  stream.on('close', () => closeSync(fd));
});
const http2 = require('node:http2');
const fs = require('node:fs');

const server = http2.createServer();
server.on('stream', (stream) => {
  const fd = fs.openSync('/some/file', 'r');

  const stat = fs.fstatSync(fd);
  const headers = {
    'content-length': stat.size,
    'last-modified': stat.mtime.toUTCString(),
    'content-type': 'text/plain; charset=utf-8',
  };
  stream.respondWithFD(fd, headers, { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });

  stream.on('close', () => fs.closeSync(fd));
});
javascript
http2stream.respondWithFile(path[, headers[, options]])#

Sends a regular file as the response. The path must specify a regular file or an 'error' event will be emitted on the Http2Stream object.

When used, the Http2Stream object's Duplex interface will be closed automatically.

The optional options.statCheck function may be specified to give user code an opportunity to set additional content headers based on the fs.Stat details of the given file:

If an error occurs while attempting to read the file data, the Http2Stream will be closed using an RST_STREAM frame using the standard INTERNAL_ERROR code. If the onError callback is defined, then it will be called. Otherwise the stream will be destroyed.

Example using a file path:

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  function statCheck(stat, headers) {
    headers['last-modified'] = stat.mtime.toUTCString();
  }

  function onError(err) {
    // stream.respond() can throw if the stream has been destroyed by
    // the other side.
    try {
      if (err.code === 'ENOENT') {
        stream.respond({ ':status': 404 });
      } else {
        stream.respond({ ':status': 500 });
      }
    } catch (err) {
      // Perform actual error handling.
      console.error(err);
    }
    stream.end();
  }

  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { statCheck, onError });
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  function statCheck(stat, headers) {
    headers['last-modified'] = stat.mtime.toUTCString();
  }

  function onError(err) {
    // stream.respond() can throw if the stream has been destroyed by
    // the other side.
    try {
      if (err.code === 'ENOENT') {
        stream.respond({ ':status': 404 });
      } else {
        stream.respond({ ':status': 500 });
      }
    } catch (err) {
      // Perform actual error handling.
      console.error(err);
    }
    stream.end();
  }

  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { statCheck, onError });
});
javascript

The options.statCheck function may also be used to cancel the send operation by returning false. For instance, a conditional request may check the stat results to determine if the file has been modified to return an appropriate 304 response:

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  function statCheck(stat, headers) {
    // Check the stat here...
    stream.respond({ ':status': 304 });
    return false; // Cancel the send operation
  }
  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { statCheck });
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  function statCheck(stat, headers) {
    // Check the stat here...
    stream.respond({ ':status': 304 });
    return false; // Cancel the send operation
  }
  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { statCheck });
});
javascript

The content-length header field will be automatically set.

The offset and length options may be used to limit the response to a specific range subset. This can be used, for instance, to support HTTP Range requests.

The options.onError function may also be used to handle all the errors that could happen before the delivery of the file is initiated. The default behavior is to destroy the stream.

When the options.waitForTrailers option is set, the 'wantTrailers' event will be emitted immediately after queuing the last chunk of payload data to be sent. The http2stream.sendTrailers() method can then be used to send trailing header fields to the peer.

When options.waitForTrailers is set, the Http2Stream will not automatically close when the final DATA frame is transmitted. User code must call either http2stream.sendTrailers() or http2stream.close() to close the Http2Stream.

import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream) => {
  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream) => {
  stream.respondWithFile('/some/file',
                         { 'content-type': 'text/plain; charset=utf-8' },
                         { waitForTrailers: true });
  stream.on('wantTrailers', () => {
    stream.sendTrailers({ ABC: 'some value to send' });
  });
});
javascript

Class: Http2Server#

Instances of Http2Server are created using the http2.createServer() function. The Http2Server class is not exported directly by the node:http2 module.

Event: 'checkContinue'#

If a 'request' listener is registered or http2.createServer() is supplied a callback function, the 'checkContinue' event is emitted each time a request with an HTTP Expect: 100-continue is received. If this event is not listened for, the server will automatically respond with a status 100 Continue as appropriate.

Handling this event involves calling response.writeContinue() if the client should continue to send the request body, or generating an appropriate HTTP response (e.g. 400 Bad Request) if the client should not continue to send the request body.

When this event is emitted and handled, the 'request' event will not be emitted.

Event: 'connection'#

This event is emitted when a new TCP stream is established. socket is typically an object of type net.Socket. Usually users will not want to access this event.

This event can also be explicitly emitted by users to inject connections into the HTTP server. In that case, any Duplex stream can be passed.

Event: 'request'#

Emitted each time there is a request. There may be multiple requests per session. See the Compatibility API.

Event: 'session'#

The 'session' event is emitted when a new Http2Session is created by the Http2Server.

Event: 'sessionError'#

The 'sessionError' event is emitted when an 'error' event is emitted by an Http2Session object associated with the Http2Server.

Event: 'stream'#
  • stream <Http2Stream> A reference to the stream
  • headers <HTTP/2 Headers Object> An object describing the headers
  • flags <number> The associated numeric flags
  • rawHeaders {HTTP/2 Raw Headers} An array containing the raw headers

The 'stream' event is emitted when a 'stream' event has been emitted by an Http2Session associated with the server.

See also Http2Session's 'stream' event.

import { createServer, constants } from 'node:http2';
const {
  HTTP2_HEADER_METHOD,
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
  HTTP2_HEADER_CONTENT_TYPE,
} = constants;

const server = createServer();
server.on('stream', (stream, headers, flags) => {
  const method = headers[HTTP2_HEADER_METHOD];
  const path = headers[HTTP2_HEADER_PATH];
  // ...
  stream.respond({
    [HTTP2_HEADER_STATUS]: 200,
    [HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
  });
  stream.write('hello ');
  stream.end('world');
});
const http2 = require('node:http2');
const {
  HTTP2_HEADER_METHOD,
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
  HTTP2_HEADER_CONTENT_TYPE,
} = http2.constants;

const server = http2.createServer();
server.on('stream', (stream, headers, flags) => {
  const method = headers[HTTP2_HEADER_METHOD];
  const path = headers[HTTP2_HEADER_PATH];
  // ...
  stream.respond({
    [HTTP2_HEADER_STATUS]: 200,
    [HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
  });
  stream.write('hello ');
  stream.end('world');
});
javascript
Event: 'timeout'#

The 'timeout' event is emitted when there is no activity on the Server for a given number of milliseconds set using http2server.setTimeout(). Default: 0 (no timeout)

server.close([callback])#

Stops the server from establishing new sessions and streams.

If callback is provided, it is not invoked until all active sessions have been closed, although the server has already stopped allowing new sessions. See net.Server.close() for more details.

server[Symbol.asyncDispose]()#

Calls server.close() and returns a promise that fulfills when the server has closed.

server.setTimeout([msecs][, callback])#

Used to set the timeout value for http2 server requests, and sets a callback function that is called when there is no activity on the Http2Server after msecs milliseconds.

The given callback is registered as a listener on the 'timeout' event.

In case if callback is not a function, a new ERR_INVALID_ARG_TYPE error will be thrown.

server.timeout#
  • Type: <number> Timeout in milliseconds. Default: 0 (no timeout)

The number of milliseconds of inactivity before a socket is presumed to have timed out.

A value of 0 will disable the timeout behavior on incoming connections.

The socket timeout logic is set up on connection, so changing this value only affects new connections to the server, not any existing connections.

server.updateSettings([settings])#

Used to update the server with the provided settings.

Throws ERR_HTTP2_INVALID_SETTING_VALUE for invalid settings values.

Throws ERR_INVALID_ARG_TYPE for invalid settings argument.

Class: Http2SecureServer#

Instances of Http2SecureServer are created using the http2.createSecureServer() function. The Http2SecureServer class is not exported directly by the node:http2 module.

Event: 'checkContinue'#

If a 'request' listener is registered or http2.createSecureServer() is supplied a callback function, the 'checkContinue' event is emitted each time a request with an HTTP Expect: 100-continue is received. If this event is not listened for, the server will automatically respond with a status 100 Continue as appropriate.

Handling this event involves calling response.writeContinue() if the client should continue to send the request body, or generating an appropriate HTTP response (e.g. 400 Bad Request) if the client should not continue to send the request body.

When this event is emitted and handled, the 'request' event will not be emitted.

Event: 'connection'#

This event is emitted when a new TCP stream is established, before the TLS handshake begins. socket is typically an object of type net.Socket. Usually users will not want to access this event.

This event can also be explicitly emitted by users to inject connections into the HTTP server. In that case, any Duplex stream can be passed.

Event: 'request'#

Emitted each time there is a request. There may be multiple requests per session. See the Compatibility API.

Event: 'session'#

The 'session' event is emitted when a new Http2Session is created by the Http2SecureServer.

Event: 'sessionError'#

The 'sessionError' event is emitted when an 'error' event is emitted by an Http2Session object associated with the Http2SecureServer.

Event: 'stream'#
  • stream <Http2Stream> A reference to the stream
  • headers <HTTP/2 Headers Object> An object describing the headers
  • flags <number> The associated numeric flags
  • rawHeaders {HTTP/2 Raw Headers} An array containing the raw headers

The 'stream' event is emitted when a 'stream' event has been emitted by an Http2Session associated with the server.

See also Http2Session's 'stream' event.

import { createSecureServer, constants } from 'node:http2';
const {
  HTTP2_HEADER_METHOD,
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
  HTTP2_HEADER_CONTENT_TYPE,
} = constants;

const options = getOptionsSomehow();

const server = createSecureServer(options);
server.on('stream', (stream, headers, flags) => {
  const method = headers[HTTP2_HEADER_METHOD];
  const path = headers[HTTP2_HEADER_PATH];
  // ...
  stream.respond({
    [HTTP2_HEADER_STATUS]: 200,
    [HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
  });
  stream.write('hello ');
  stream.end('world');
});
const http2 = require('node:http2');
const {
  HTTP2_HEADER_METHOD,
  HTTP2_HEADER_PATH,
  HTTP2_HEADER_STATUS,
  HTTP2_HEADER_CONTENT_TYPE,
} = http2.constants;

const options = getOptionsSomehow();

const server = http2.createSecureServer(options);
server.on('stream', (stream, headers, flags) => {
  const method = headers[HTTP2_HEADER_METHOD];
  const path = headers[HTTP2_HEADER_PATH];
  // ...
  stream.respond({
    [HTTP2_HEADER_STATUS]: 200,
    [HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
  });
  stream.write('hello ');
  stream.end('world');
});
javascript
Event: 'timeout'#

The 'timeout' event is emitted when there is no activity on the Server for a given number of milliseconds set using http2secureServer.setTimeout(). Default: 0 (no timeout)

Event: 'unknownProtocol'#

The 'unknownProtocol' event is emitted when a connecting client fails to negotiate an allowed protocol (i.e. HTTP/2 or HTTP/1.1). The event handler receives the socket for handling. If no listener is registered for this event, the connection is terminated. A timeout may be specified using the 'unknownProtocolTimeout' option passed to http2.createSecureServer().

In earlier versions of Node.js, this event would be emitted if allowHTTP1 is false and, during the TLS handshake, the client either does not send an ALPN extension or sends an ALPN extension that does not include HTTP/2 (h2). Newer versions of Node.js only emit this event if allowHTTP1 is false and the client does not send an ALPN extension. If the client sends an ALPN extension that does not include HTTP/2 (or HTTP/1.1 if allowHTTP1 is true), the TLS handshake will fail and no secure connection will be established.

See the Compatibility API.

server.close([callback])#

Stops the server from establishing new sessions and streams.

If callback is provided, it is not invoked until all active sessions have been closed, although the server has already stopped allowing new sessions. See tls.Server.close() for more details.

server.setTimeout([msecs][, callback])#

Used to set the timeout value for http2 secure server requests, and sets a callback function that is called when there is no activity on the Http2SecureServer after msecs milliseconds.

The given callback is registered as a listener on the 'timeout' event.

In case if callback is not a function, a new ERR_INVALID_ARG_TYPE error will be thrown.

server.timeout#
  • Type: <number> Timeout in milliseconds. Default: 0 (no timeout)

The number of milliseconds of inactivity before a socket is presumed to have timed out.

A value of 0 will disable the timeout behavior on incoming connections.

The socket timeout logic is set up on connection, so changing this value only affects new connections to the server, not any existing connections.

server.updateSettings([settings])#

Used to update the server with the provided settings.

Throws ERR_HTTP2_INVALID_SETTING_VALUE for invalid settings values.

Throws ERR_INVALID_ARG_TYPE for invalid settings argument.

http2.createServer([options][, onRequestHandler])#

  • options <Object>
    • maxDeflateDynamicTableSize <number> Sets the maximum dynamic table size for deflating header fields. Default: 4Kib.
    • maxSettings <number> Sets the maximum number of settings entries per SETTINGS frame. The minimum value allowed is 1. Default: 32.
    • maxSessionMemory<number> Sets the maximum memory that the Http2Session is permitted to use. The value is expressed in terms of number of megabytes, e.g. 1 equal 1 megabyte. The minimum value allowed is 1. This is a credit based limit, existing Http2Streams may cause this limit to be exceeded, but new Http2Stream instances will be rejected while this limit is exceeded. The current number of Http2Stream sessions, the current memory use of the header compression tables, header blocks retained by open streams, current data queued to be sent, and unacknowledged PING and SETTINGS frames are all counted towards the current limit. Default: 10.
    • maxHeaderListPairs <number> Sets the maximum number of header entries. This is similar to server.maxHeadersCount or request.maxHeadersCount in the node:http module. The minimum value is 4. Default: 128.
    • maxOutstandingPings <number> Sets the maximum number of outstanding, unacknowledged pings. Default: 10.
    • maxSendHeaderBlockLength <number> Sets the maximum allowed size for a serialized, compressed block of headers. Attempts to send headers that exceed this limit will result in a 'frameError' event being emitted and the stream being closed and destroyed. While this sets the maximum allowed size to the entire block of headers, nghttp2 (the internal http2 library) has a limit of 65536 for each decompressed key/value pair.
    • paddingStrategy <number> The strategy used for determining the amount of padding to use for HEADERS and DATA frames. Default: http2.constants.PADDING_STRATEGY_NONE. Value may be one of:
      • http2.constants.PADDING_STRATEGY_NONE: No padding is applied.
      • http2.constants.PADDING_STRATEGY_MAX: The maximum amount of padding, determined by the internal implementation, is applied.
      • http2.constants.PADDING_STRATEGY_ALIGNED: Attempts to apply enough padding to ensure that the total frame length, including the 9-byte header, is a multiple of 8. For each frame, there is a maximum allowed number of padding bytes that is determined by current flow control state and settings. If this maximum is less than the calculated amount needed to ensure alignment, the maximum is used and the total frame length is not necessarily aligned at 8 bytes.
    • peerMaxConcurrentStreams <number> Sets the maximum number of concurrent streams for the remote peer as if a SETTINGS frame had been received. Will be overridden if the remote peer sets its own value for maxConcurrentStreams. Default: 100.
    • maxSessionInvalidFrames <integer> Sets the maximum number of invalid frames that will be tolerated before the session is closed. Default: 1000.
    • maxSessionRejectedStreams <integer> Sets the maximum number of rejected upon creation streams that will be tolerated before the session is closed. Each rejection is associated with an NGHTTP2_ENHANCE_YOUR_CALM error that should tell the peer to not open any more streams, continuing to open streams is therefore regarded as a sign of a misbehaving peer. Default: 100.
    • settings <HTTP/2 Settings Object> The initial settings to send to the remote peer upon connection.
    • streamResetBurst <number> and streamResetRate <number> Sets the rate limit for the incoming stream reset (RST_STREAM frame). Both settings must be set to have any effect, and default to 1000 and 33 respectively.
    • remoteCustomSettings <Array> The array of integer values determines the settings types, which are included in the CustomSettings-property of the received remoteSettings. Please see the CustomSettings-property of the Http2Settings object for more information, on the allowed setting types.
    • Http1IncomingMessage <http.IncomingMessage> Specifies the IncomingMessage class to used for HTTP/1 fallback. Useful for extending the original http.IncomingMessage. Default: http.IncomingMessage. Deprecated. Use http1Options.IncomingMessage instead. See DEP0202.
    • Http1ServerResponse <http.ServerResponse> Specifies the ServerResponse class to used for HTTP/1 fallback. Useful for extending the original http.ServerResponse. Default: http.ServerResponse. Deprecated. Use http1Options.ServerResponse instead. See DEP0202.
    • http1Options <Object> An options object for configuring the HTTP/1 fallback when allowHTTP1 is true. These options are passed to the underlying HTTP/1 server. See http.createServer() for available options. Among others, the following are supported:
      • IncomingMessage <http.IncomingMessage> Specifies the IncomingMessage class to use for HTTP/1 fallback. Default: http.IncomingMessage.
      • ServerResponse <http.ServerResponse> Specifies the ServerResponse class to use for HTTP/1 fallback. Default: http.ServerResponse.
      • keepAliveTimeout <number> The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. Default: 5000.
    • Http2ServerRequest <http2.Http2ServerRequest> Specifies the Http2ServerRequest class to use. Useful for extending the original Http2ServerRequest. Default: Http2ServerRequest.
    • Http2ServerResponse <http2.Http2ServerResponse> Specifies the Http2ServerResponse class to use. Useful for extending the original Http2ServerResponse. Default: Http2ServerResponse.
    • unknownProtocolTimeout <number> Specifies a timeout in milliseconds that a server should wait when an 'unknownProtocol' is emitted. If the socket has not been destroyed by that time the server will destroy it. Default: 10000.
    • strictFieldWhitespaceValidation <boolean> If true, it turns on strict leading and trailing whitespace validation for HTTP/2 header field names and values as per RFC-9113. Default: true.
    • strictSingleValueFields <boolean> If true, strict validation is used for headers and trailers defined as having only a single value, such that an error is thrown if multiple values are provided. Default: true.
    • ...options <Object> Any net.createServer() option can be provided.
  • onRequestHandler <Function> See Compatibility API
  • Returns: <Http2Server>

Returns a net.Server instance that creates and manages Http2Session instances.

Since there are no browsers known that support unencrypted HTTP/2, the use of http2.createSecureServer() is necessary when communicating with browser clients.

import { createServer } from 'node:http2';

// Create an unencrypted HTTP/2 server.
// Since there are no browsers known that support
// unencrypted HTTP/2, the use of `createSecureServer()`
// is necessary when communicating with browser clients.
const server = createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8000);
const http2 = require('node:http2');

// Create an unencrypted HTTP/2 server.
// Since there are no browsers known that support
// unencrypted HTTP/2, the use of `http2.createSecureServer()`
// is necessary when communicating with browser clients.
const server = http2.createServer();

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8000);
javascript

http2.createSecureServer(options[, onRequestHandler])#

  • options <Object>
    • allowHTTP1 <boolean> Incoming client connections that do not support HTTP/2 will be downgraded to HTTP/1.x when set to true. See the 'unknownProtocol' event. See ALPN negotiation. Default: false.
    • maxDeflateDynamicTableSize <number> Sets the maximum dynamic table size for deflating header fields. Default: 4Kib.
    • maxSettings <number> Sets the maximum number of settings entries per SETTINGS frame. The minimum value allowed is 1. Default: 32.
    • maxSessionMemory<number> Sets the maximum memory that the Http2Session is permitted to use. The value is expressed in terms of number of megabytes, e.g. 1 equal 1 megabyte. The minimum value allowed is 1. This is a credit based limit, existing Http2Streams may cause this limit to be exceeded, but new Http2Stream instances will be rejected while this limit is exceeded. The current number of Http2Stream sessions, the current memory use of the header compression tables, header blocks retained by open streams, current data queued to be sent, and unacknowledged PING and SETTINGS frames are all counted towards the current limit. Default: 10.
    • maxHeaderListPairs <number> Sets the maximum number of header entries. This is similar to server.maxHeadersCount or request.maxHeadersCount in the node:http module. The minimum value is 4. Default: 128.
    • maxOutstandingPings <number> Sets the maximum number of outstanding, unacknowledged pings. Default: 10.
    • maxSendHeaderBlockLength <number> Sets the maximum allowed size for a serialized, compressed block of headers. Attempts to send headers that exceed this limit will result in a 'frameError' event being emitted and the stream being closed and destroyed.
    • paddingStrategy <number> Strategy used for determining the amount of padding to use for HEADERS and DATA frames. Default: http2.constants.PADDING_STRATEGY_NONE. Value may be one of:
      • http2.constants.PADDING_STRATEGY_NONE: No padding is applied.
      • http2.constants.PADDING_STRATEGY_MAX: The maximum amount of padding, determined by the internal implementation, is applied.
      • http2.constants.PADDING_STRATEGY_ALIGNED: Attempts to apply enough padding to ensure that the total frame length, including the 9-byte header, is a multiple of 8. For each frame, there is a maximum allowed number of padding bytes that is determined by current flow control state and settings. If this maximum is less than the calculated amount needed to ensure alignment, the maximum is used and the total frame length is not necessarily aligned at 8 bytes.
    • peerMaxConcurrentStreams <number> Sets the maximum number of concurrent streams for the remote peer as if a SETTINGS frame had been received. Will be overridden if the remote peer sets its own value for maxConcurrentStreams. Default: 100.
    • maxSessionInvalidFrames <integer> Sets the maximum number of invalid frames that will be tolerated before the session is closed. Default: 1000.
    • maxSessionRejectedStreams <integer> Sets the maximum number of rejected upon creation streams that will be tolerated before the session is closed. Each rejection is associated with an NGHTTP2_ENHANCE_YOUR_CALM error that should tell the peer to not open any more streams, continuing to open streams is therefore regarded as a sign of a misbehaving peer. Default: 100.
    • settings <HTTP/2 Settings Object> The initial settings to send to the remote peer upon connection.
    • streamResetBurst <number> and streamResetRate <number> Sets the rate limit for the incoming stream reset (RST_STREAM frame). Both settings must be set to have any effect, and default to 1000 and 33 respectively.
    • remoteCustomSettings <Array> The array of integer values determines the settings types, which are included in the customSettings-property of the received remoteSettings. Please see the customSettings-property of the Http2Settings object for more information, on the allowed setting types.
    • ...options <Object> Any tls.createServer() options can be provided. For servers, the identity options (pfx or key/cert) are usually required.
    • origins <string>[] An array of origin strings to send within an ORIGIN frame immediately following creation of a new server Http2Session.
    • unknownProtocolTimeout <number> Specifies a timeout in milliseconds that a server should wait when an 'unknownProtocol' event is emitted. If the socket has not been destroyed by that time the server will destroy it. Default: 10000.
    • strictFieldWhitespaceValidation <boolean> If true, it turns on strict leading and trailing whitespace validation for HTTP/2 header field names and values as per RFC-9113. Default: true.
    • strictSingleValueFields <boolean> If true, strict validation is used for headers and trailers defined as having only a single value, such that an error is thrown if multiple values are provided. Default: true.
    • http1Options <Object> An options object for configuring the HTTP/1 fallback when allowHTTP1 is true. These options are passed to the underlying HTTP/1 server. See http.createServer() for available options. Among others, the following are supported:
      • IncomingMessage <http.IncomingMessage> Specifies the IncomingMessage class to use for HTTP/1 fallback. Default: http.IncomingMessage.
      • ServerResponse <http.ServerResponse> Specifies the ServerResponse class to use for HTTP/1 fallback. Default: http.ServerResponse.
      • keepAliveTimeout <number> The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. Default: 5000.
  • onRequestHandler <Function> See Compatibility API
  • Returns: <Http2SecureServer>

Returns a tls.Server instance that creates and manages Http2Session instances.

import { createSecureServer } from 'node:http2';
import { readFileSync } from 'node:fs';

const options = {
  key: readFileSync('server-key.pem'),
  cert: readFileSync('server-cert.pem'),
};

// Create a secure HTTP/2 server
const server = createSecureServer(options);

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8443);
const http2 = require('node:http2');
const fs = require('node:fs');

const options = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
};

// Create a secure HTTP/2 server
const server = http2.createSecureServer(options);

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200,
  });
  stream.end('<h1>Hello World</h1>');
});

server.listen(8443);
javascript

http2.connect(authority[, options][, listener])#

  • authority <string> | <URL> The remote HTTP/2 server to connect to. This must be in the form of a minimal, valid URL with the http:// or https:// prefix, host name, and IP port (if a non-default port is used). Userinfo (user ID and password), path, querystring, and fragment details in the URL will be ignored.
  • options <Object>
    • maxDeflateDynamicTableSize <number> Sets the maximum dynamic table size for deflating header fields. Default: 4Kib.
    • maxSettings <number> Sets the maximum number of settings entries per SETTINGS frame. The minimum value allowed is 1. Default: 32.
    • maxSessionMemory<number> Sets the maximum memory that the Http2Session is permitted to use. The value is expressed in terms of number of megabytes, e.g. 1 equal 1 megabyte. The minimum value allowed is 1. This is a credit based limit, existing Http2Streams may cause this limit to be exceeded, but new Http2Stream instances will be rejected while this limit is exceeded. The current number of Http2Stream sessions, the current memory use of the header compression tables, header blocks retained by open streams, current data queued to be sent, and unacknowledged PING and SETTINGS frames are all counted towards the current limit. Default: 10.
    • maxHeaderListPairs <number> Sets the maximum number of header entries. This is similar to server.maxHeadersCount or request.maxHeadersCount in the node:http module. The minimum value is 1. Default: 128.
    • maxOriginSetSize <number> Sets the maximum number of uniq origin the sever can send via ORIGIN frames. Default: 128.
    • maxOutstandingPings <number> Sets the maximum number of outstanding, unacknowledged pings. Default: 10.
    • maxReservedRemoteStreams <number> Sets the maximum number of reserved push streams the client will accept at any given time. Once the current number of currently reserved push streams exceeds reaches this limit, new push streams sent by the server will be automatically rejected. The minimum allowed value is 0. The maximum allowed value is 232-1. A negative value sets this option to the maximum allowed value. Default: 200.
    • maxSendHeaderBlockLength <number> Sets the maximum allowed size for a serialized, compressed block of headers. Attempts to send headers that exceed this limit will result in a 'frameError' event being emitted and the stream being closed and destroyed.
    • paddingStrategy <number> Strategy used for determining the amount of padding to use for HEADERS and DATA frames. Default: http2.constants.PADDING_STRATEGY_NONE. Value may be one of:
      • http2.constants.PADDING_STRATEGY_NONE: No padding is applied.
      • http2.constants.PADDING_STRATEGY_MAX: The maximum amount of padding, determined by the internal implementation, is applied.
      • http2.constants.PADDING_STRATEGY_ALIGNED: Attempts to apply enough padding to ensure that the total frame length, including the 9-byte header, is a multiple of 8. For each frame, there is a maximum allowed number of padding bytes that is determined by current flow control state and settings. If this maximum is less than the calculated amount needed to ensure alignment, the maximum is used and the total frame length is not necessarily aligned at 8 bytes.
    • peerMaxConcurrentStreams <number> Sets the maximum number of concurrent streams for the remote peer as if a SETTINGS frame had been received. Will be overridden if the remote peer sets its own value for maxConcurrentStreams. Default: 100.
    • protocol <string> The protocol to connect with, if not set in the authority. Value may be either 'http:' or 'https:'. Default: 'https:'
    • settings <HTTP/2 Settings Object> The initial settings to send to the remote peer upon connection.
    • remoteCustomSettings <Array> The array of integer values determines the settings types, which are included in the CustomSettings-property of the received remoteSettings. Please see the CustomSettings-property of the Http2Settings object for more information, on the allowed setting types.
    • createConnection <Function> An optional callback that receives the URL instance passed to connect and the options object, and returns any Duplex stream that is to be used as the connection for this session.
    • ...options <Object> Any net.connect() or tls.connect() options can be provided.
    • unknownProtocolTimeout <number> Specifies a timeout in milliseconds that a server should wait when an 'unknownProtocol' event is emitted. If the socket has not been destroyed by that time the server will destroy it. Default: 10000.
    • strictFieldWhitespaceValidation <boolean> If true, it turns on strict leading and trailing whitespace validation for HTTP/2 header field names and values as per RFC-9113. Default: true.
  • listener <Function> Will be registered as a one-time listener of the 'connect' event.
  • Returns: <ClientHttp2Session>

Returns a ClientHttp2Session instance.

import { connect } from 'node:http2';
const client = connect('https://localhost:1234');

/* Use the client */

client.close();
const http2 = require('node:http2');
const client = http2.connect('https://localhost:1234');

/* Use the client */

client.close();
javascript

http2.constants#

Error codes for RST_STREAM and GOAWAY#
Value Name Constant
0x00 No Error http2.constants.NGHTTP2_NO_ERROR
0x01 Protocol Error http2.constants.NGHTTP2_PROTOCOL_ERROR
0x02 Internal Error http2.constants.NGHTTP2_INTERNAL_ERROR
0x03 Flow Control Error http2.constants.NGHTTP2_FLOW_CONTROL_ERROR
0x04 Settings Timeout http2.constants.NGHTTP2_SETTINGS_TIMEOUT
0x05 Stream Closed http2.constants.NGHTTP2_STREAM_CLOSED
0x06 Frame Size Error http2.constants.NGHTTP2_FRAME_SIZE_ERROR
0x07 Refused Stream http2.constants.NGHTTP2_REFUSED_STREAM
0x08 Cancel http2.constants.NGHTTP2_CANCEL
0x09 Compression Error http2.constants.NGHTTP2_COMPRESSION_ERROR
0x0a Connect Error http2.constants.NGHTTP2_CONNECT_ERROR
0x0b Enhance Your Calm http2.constants.NGHTTP2_ENHANCE_YOUR_CALM
0x0c Inadequate Security http2.constants.NGHTTP2_INADEQUATE_SECURITY
0x0d HTTP/1.1 Required http2.constants.NGHTTP2_HTTP_1_1_REQUIRED

The 'timeout' event is emitted when there is no activity on the Server for a given number of milliseconds set using http2server.setTimeout().

http2.getDefaultSettings()#

Returns an object containing the default settings for an Http2Session instance. This method returns a new object instance every time it is called so instances returned may be safely modified for use.

http2.getPackedSettings([settings])#

Returns a Buffer instance containing serialized representation of the given HTTP/2 settings as specified in the HTTP/2 specification. This is intended for use with the HTTP2-Settings header field.

import { getPackedSettings } from 'node:http2';

const packed = getPackedSettings({ enablePush: false });

console.log(packed.toString('base64'));
// Prints: AAIAAAAA
const http2 = require('node:http2');

const packed = http2.getPackedSettings({ enablePush: false });

console.log(packed.toString('base64'));
// Prints: AAIAAAAA
javascript

http2.getUnpackedSettings(buf)#

Returns a HTTP/2 Settings Object containing the deserialized settings from the given Buffer as generated by http2.getPackedSettings().

http2.performServerHandshake(socket[, options])#

Create an HTTP/2 server session from an existing socket.

http2.sensitiveHeaders#

This symbol can be set as a property on the HTTP/2 headers object with an array value in order to provide a list of headers considered sensitive. See Sensitive headers for more details.

Headers object#

Headers are represented as own-properties on JavaScript objects. The property keys will be serialized to lower-case. Property values should be strings (if they are not they will be coerced to strings) or an Array of strings (in order to send more than one value per header field).

const headers = {
  ':status': '200',
  'content-type': 'text-plain',
  'ABC': ['has', 'more', 'than', 'one', 'value'],
};

stream.respond(headers);
js

Header objects passed to callback functions will have a null prototype. This means that normal JavaScript object methods such as Object.prototype.toString() and Object.prototype.hasOwnProperty() will not work.

For incoming headers:

  • The :status header is converted to number.
  • Duplicates of :status, :method, :authority, :scheme, :path, :protocol, age, authorization, access-control-allow-credentials, access-control-max-age, access-control-request-method, content-encoding, content-language, content-length, content-location, content-md5, content-range, content-type, date, dnt, etag, expires, from, host, if-match, if-modified-since, if-none-match, if-range, if-unmodified-since, last-modified, location, max-forwards, proxy-authorization, range, referer,retry-after, tk, upgrade-insecure-requests, user-agent or x-content-type-options are discarded.
  • set-cookie is always an array. Duplicates are added to the array.
  • For duplicate cookie headers, the values are joined together with '; '.
  • For all other headers, the values are joined together with ', '.
import { createServer } from 'node:http2';
const server = createServer();
server.on('stream', (stream, headers) => {
  console.log(headers[':path']);
  console.log(headers.ABC);
});
const http2 = require('node:http2');
const server = http2.createServer();
server.on('stream', (stream, headers) => {
  console.log(headers[':path']);
  console.log(headers.ABC);
});
javascript
Raw headers#

In some APIs, in addition to object format, headers can also be passed or accessed as a raw flat array, preserving details of ordering and duplicate keys to match the raw transmission format.

In this format the keys and values are in the same list. It is not a list of tuples. So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values. Duplicate headers are not merged and so each key-value pair will appear separately.

This can be useful for cases such as proxies, where existing headers should be exactly forwarded as received, or as a performance optimization when the headers are already available in raw format.

const rawHeaders = [
  ':status',
  '404',
  'content-type',
  'text/plain',
];

stream.respond(rawHeaders);
js
Sensitive headers#

HTTP2 headers can be marked as sensitive, which means that the HTTP/2 header compression algorithm will never index them. This can make sense for header values with low entropy and that may be considered valuable to an attacker, for example Cookie or Authorization. To achieve this, add the header name to the [http2.sensitiveHeaders] property as an array:

const headers = {
  ':status': '200',
  'content-type': 'text-plain',
  'cookie': 'some-cookie',
  'other-sensitive-header': 'very secret data',
  [http2.sensitiveHeaders]: ['cookie', 'other-sensitive-header'],
};

stream.respond(headers);
js

For some headers, such as Authorization and short Cookie headers, this flag is set automatically.

This property is also set for received headers. It will contain the names of all headers marked as sensitive, including ones marked that way automatically.

For raw headers, this should still be set as a property on the array, like rawHeadersArray[http2.sensitiveHeaders] = ['cookie'], not as a separate key and value pair within the array itself.

Settings object#

The http2.getDefaultSettings(), http2.getPackedSettings(), http2.createServer(), http2.createSecureServer(), http2session.settings(), http2session.localSettings, and http2session.remoteSettings APIs either return or receive as input an object that defines configuration settings for an Http2Session object. These objects are ordinary JavaScript objects containing the following properties.

  • headerTableSize <number> Specifies the maximum number of bytes used for header compression. The minimum allowed value is 0. The maximum allowed value is 232-1. Default: 4096.
  • enablePush <boolean> Specifies true if HTTP/2 Push Streams are to be permitted on the Http2Session instances. Default: true.
  • initialWindowSize <number> Specifies the sender's initial window size in bytes for stream-level flow control. The minimum allowed value is 0. The maximum allowed value is 232-1. Default: 65535.
  • maxFrameSize <number> Specifies the size in bytes of the largest frame payload. The minimum allowed value is 16,384. The maximum allowed value is 224-1. Default: 16384.
  • maxConcurrentStreams <number> Specifies the maximum number of concurrent streams permitted on an Http2Session. There is no default value which implies, at least theoretically, 232-1 streams may be open concurrently at any given time in an Http2Session. The minimum value is 0. The maximum allowed value is 232-1. Default: 4294967295.
  • maxHeaderListSize <number> Specifies the maximum size (uncompressed octets) of header list that will be accepted. The minimum allowed value is 0. The maximum allowed value is 232-1. Default: 65535.
  • maxHeaderSize <number> Alias for maxHeaderListSize.
  • enableConnectProtocol<boolean> Specifies true if the "Extended Connect Protocol" defined by RFC 8441 is to be enabled. This setting is only meaningful if sent by the server. Once the enableConnectProtocol setting has been enabled for a given Http2Session, it cannot be disabled. Default: false.
  • customSettings <Object> Specifies additional settings, yet not implemented in node and the underlying libraries. The key of the object defines the numeric value of the settings type (as defined in the "HTTP/2 SETTINGS" registry established by [RFC 7540]) and the values the actual numeric value of the settings. The settings type has to be an integer in the range from 1 to 2^16-1. It should not be a settings type already handled by node, i.e. currently it should be greater than 6, although it is not an error. The values need to be unsigned integers in the range from 0 to 2^32-1. Currently, a maximum of up 10 custom settings is supported. It is only supported for sending SETTINGS, or for receiving settings values specified in the remoteCustomSettings options of the server or client object. Do not mix the customSettings-mechanism for a settings id with interfaces for the natively handled settings, in case a setting becomes natively supported in a future node version.

All additional properties on the settings object are ignored.

Error handling#

There are several types of error conditions that may arise when using the node:http2 module:

Validation errors occur when an incorrect argument, option, or setting value is passed in. These will always be reported by a synchronous throw.

State errors occur when an action is attempted at an incorrect time (for instance, attempting to send data on a stream after it has closed). These will be reported using either a synchronous throw or via an 'error' event on the Http2Stream, Http2Session or HTTP/2 Server objects, depending on where and when the error occurs.

Internal errors occur when an HTTP/2 session fails unexpectedly. These will be reported via an 'error' event on the Http2Session or HTTP/2 Server objects.

Protocol errors occur when various HTTP/2 protocol constraints are violated. These will be reported using either a synchronous throw or via an 'error' event on the Http2Stream, Http2Session or HTTP/2 Server objects, depending on where and when the error occurs.

Invalid character handling in header names and values#

The HTTP/2 implementation applies stricter handling of invalid characters in HTTP header names and values than the HTTP/1 implementation.

Header field names are case-insensitive and are transmitted over the wire strictly as lower-case strings. The API provided by Node.js allows header names to be set as mixed-case strings (e.g. Content-Type) but will convert those to lower-case (e.g. content-type) upon transmission.

Header field-names must only contain one or more of the following ASCII characters: a-z, A-Z, 0-9, !, #, $, %, &, ', *, +, -, ., ^, _, ` (backtick), |, and ~.

Using invalid characters within an HTTP header field name will cause the stream to be closed with a protocol error being reported.

Header field values are handled with more leniency but should not contain new-line or carriage return characters and should be limited to US-ASCII characters, per the requirements of the HTTP specification.

Push streams on the client#

To receive pushed streams on the client, set a listener for the 'stream' event on the ClientHttp2Session:

import { connect } from 'node:http2';

const client = connect('http://localhost');

client.on('stream', (pushedStream, requestHeaders) => {
  pushedStream.on('push', (responseHeaders) => {
    // Process response headers
  });
  pushedStream.on('data', (chunk) => { /* handle pushed data */ });
});

const req = client.request({ ':path': '/' });
const http2 = require('node:http2');

const client = http2.connect('http://localhost');

client.on('stream', (pushedStream, requestHeaders) => {
  pushedStream.on('push', (responseHeaders) => {
    // Process response headers
  });
  pushedStream.on('data', (chunk) => { /* handle pushed data */ });
});

const req = client.request({ ':path': '/' });
javascript

Supporting the CONNECT method#

The CONNECT method is used to allow an HTTP/2 server to be used as a proxy for TCP/IP connections.

A simple TCP Server:

import { createServer } from 'node:net';

const server = createServer((socket) => {
  let name = '';
  socket.setEncoding('utf8');
  socket.on('data', (chunk) => name += chunk);
  socket.on('end', () => socket.end(`hello ${name}`));
});

server.listen(8000);
const net = require('node:net');

const server = net.createServer((socket) => {
  let name = '';
  socket.setEncoding('utf8');
  socket.on('data', (chunk) => name += chunk);
  socket.on('end', () => socket.end(`hello ${name}`));
});

server.listen(8000);
javascript

An HTTP/2 CONNECT proxy:

import { createServer, constants } from 'node:http2';
const { NGHTTP2_REFUSED_STREAM, NGHTTP2_CONNECT_ERROR } = constants;
import { connect } from 'node:net';

const proxy = createServer();
proxy.on('stream', (stream, headers) => {
  if (headers[':method'] !== 'CONNECT') {
    // Only accept CONNECT requests
    stream.close(NGHTTP2_REFUSED_STREAM);
    return;
  }
  const auth = new URL(`tcp://${headers[':authority']}`);
  // It's a very good idea to verify that hostname and port are
  // things this proxy should be connecting to.
  const socket = connect(auth.port, auth.hostname, () => {
    stream.respond();
    socket.pipe(stream);
    stream.pipe(socket);
  });
  socket.on('error', (error) => {
    stream.close(NGHTTP2_CONNECT_ERROR);
  });
});

proxy.listen(8001);
const http2 = require('node:http2');
const { NGHTTP2_REFUSED_STREAM } = http2.constants;
const net = require('node:net');

const proxy = http2.createServer();
proxy.on('stream', (stream, headers) => {
  if (headers[':method'] !== 'CONNECT') {
    // Only accept CONNECT requests
    stream.close(NGHTTP2_REFUSED_STREAM);
    return;
  }
  const auth = new URL(`tcp://${headers[':authority']}`);
  // It's a very good idea to verify that hostname and port are
  // things this proxy should be connecting to.
  const socket = net.connect(auth.port, auth.hostname, () => {
    stream.respond();
    socket.pipe(stream);
    stream.pipe(socket);
  });
  socket.on('error', (error) => {
    stream.close(http2.constants.NGHTTP2_CONNECT_ERROR);
  });
});

proxy.listen(8001);
javascript

An HTTP/2 CONNECT client:

import { connect, constants } from 'node:http2';

const client = connect('http://localhost:8001');

// Must not specify the ':path' and ':scheme' headers
// for CONNECT requests or an error will be thrown.
const req = client.request({
  ':method': 'CONNECT',
  ':authority': 'localhost:8000',
});

req.on('response', (headers) => {
  console.log(headers[constants.HTTP2_HEADER_STATUS]);
});
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => data += chunk);
req.on('end', () => {
  console.log(`The server says: ${data}`);
  client.close();
});
req.end('Jane');
const http2 = require('node:http2');

const client = http2.connect('http://localhost:8001');

// Must not specify the ':path' and ':scheme' headers
// for CONNECT requests or an error will be thrown.
const req = client.request({
  ':method': 'CONNECT',
  ':authority': 'localhost:8000',
});

req.on('response', (headers) => {
  console.log(headers[http2.constants.HTTP2_HEADER_STATUS]);
});
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => data += chunk);
req.on('end', () => {
  console.log(`The server says: ${data}`);
  client.close();
});
req.end('Jane');
javascript

The extended CONNECT protocol#

RFC 8441 defines an "Extended CONNECT Protocol" extension to HTTP/2 that may be used to bootstrap the use of an Http2Stream using the CONNECT method as a tunnel for other communication protocols (such as WebSockets).

The use of the Extended CONNECT Protocol is enabled by HTTP/2 servers by using the enableConnectProtocol setting:

import { createServer } from 'node:http2';
const settings = { enableConnectProtocol: true };
const server = createServer({ settings });
const http2 = require('node:http2');
const settings = { enableConnectProtocol: true };
const server = http2.createServer({ settings });
javascript

Once the client receives the SETTINGS frame from the server indicating that the extended CONNECT may be used, it may send CONNECT requests that use the ':protocol' HTTP/2 pseudo-header:

import { connect } from 'node:http2';
const client = connect('http://localhost:8080');
client.on('remoteSettings', (settings) => {
  if (settings.enableConnectProtocol) {
    const req = client.request({ ':method': 'CONNECT', ':protocol': 'foo' });
    // ...
  }
});
const http2 = require('node:http2');
const client = http2.connect('http://localhost:8080');
client.on('remoteSettings', (settings) => {
  if (settings.enableConnectProtocol) {
    const req = client.request({ ':method': 'CONNECT', ':protocol': 'foo' });
    // ...
  }
});
javascript

Compatibility API#

The Compatibility API has the goal of providing a similar developer experience of HTTP/1 when using HTTP/2, making it possible to develop applications that support both HTTP/1 and HTTP/2. This API targets only the public API of the HTTP/1. However many modules use internal methods or state, and those are not supported as it is a completely different implementation.

The following example creates an HTTP/2 server using the compatibility API:

import { createServer } from 'node:http2';
const server = createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('ok');
});
const http2 = require('node:http2');
const server = http2.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('ok');
});
javascript

In order to create a mixed HTTPS and HTTP/2 server, refer to the ALPN negotiation section. Upgrading from non-tls HTTP/1 servers is not supported.

The HTTP/2 compatibility API is composed of Http2ServerRequest and Http2ServerResponse. They aim at API compatibility with HTTP/1, but they do not hide the differences between the protocols. As an example, the status message for HTTP codes is ignored.

ALPN negotiation#

ALPN negotiation allows supporting both HTTPS and HTTP/2 over the same socket. The req and res objects can be either HTTP/1 or HTTP/2, and an application must restrict itself to the public API of HTTP/1, and detect if it is possible to use the more advanced features of HTTP/2.

The following example creates a server that supports both protocols:

import { createSecureServer } from 'node:http2';
import { readFileSync } from 'node:fs';

const cert = readFileSync('./cert.pem');
const key = readFileSync('./key.pem');

const server = createSecureServer(
  { cert, key, allowHTTP1: true },
  onRequest,
).listen(8000);

function onRequest(req, res) {
  // Detects if it is an HTTPS request or HTTP/2
  const { socket: { alpnProtocol } } = req.httpVersion === '2.0' ?
    req.stream.session : req;
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({
    alpnProtocol,
    httpVersion: req.httpVersion,
  }));
}
const { createSecureServer } = require('node:http2');
const { readFileSync } = require('node:fs');

const cert = readFileSync('./cert.pem');
const key = readFileSync('./key.pem');

const server = createSecureServer(
  { cert, key, allowHTTP1: true },
  onRequest,
).listen(4443);

function onRequest(req, res) {
  // Detects if it is an HTTPS request or HTTP/2
  const { socket: { alpnProtocol } } = req.httpVersion === '2.0' ?
    req.stream.session : req;
  res.writeHead(200, { 'content-type': 'application/json' });
  res.end(JSON.stringify({
    alpnProtocol,
    httpVersion: req.httpVersion,
  }));
}
javascript

The 'request' event works identically on both HTTPS and HTTP/2.

Class: http2.Http2ServerRequest#

A Http2ServerRequest object is created by http2.Server or http2.SecureServer and passed as the first argument to the 'request' event. It may be used to access a request status, headers, and data.

Event: 'aborted'#

The 'aborted' event is emitted whenever a Http2ServerRequest instance is abnormally aborted in mid-communication.

The 'aborted' event will only be emitted if the Http2ServerRequest writable side has not been ended.

Event: 'close'#

Indicates that the underlying Http2Stream was closed. Just like 'end', this event occurs only once per response.

request.aborted#

The request.aborted property will be true if the request has been aborted.

request.authority#

The request authority pseudo header field. Because HTTP/2 allows requests to set either :authority or host, this value is derived from req.headers[':authority'] if present. Otherwise, it is derived from req.headers['host'].

request.complete#

The request.complete property will be true if the request has been completed, aborted, or destroyed.

request.connection#

Stability: 0 - Deprecated. Use request.socket.

See request.socket.

request.destroy([error])#

Calls destroy() on the Http2Stream that received the Http2ServerRequest. If error is provided, an 'error' event is emitted and error is passed as an argument to any listeners on the event.

It does nothing if the stream was already destroyed.

request.headers#

The request/response headers object.

Key-value pairs of header names and values. Header names are lower-cased.

// Prints something like:
//
// { 'user-agent': 'curl/7.22.0',
//   host: '127.0.0.1:8000',
//   accept: '*/*' }
console.log(request.headers);
js

See HTTP/2 Headers Object.

In HTTP/2, the request path, host name, protocol, and method are represented as special headers prefixed with the : character (e.g. ':path'). These special headers will be included in the request.headers object. Care must be taken not to inadvertently modify these special headers or errors may occur. For instance, removing all headers from the request will cause errors to occur:

removeAllHeaders(request.headers);
assert(request.url);   // Fails because the :path header has been removed
js
request.httpVersion#

In case of server request, the HTTP version sent by the client. In the case of client response, the HTTP version of the connected-to server. Returns '2.0'.

Also message.httpVersionMajor is the first integer and message.httpVersionMinor is the second.

request.method#

The request method as a string. Read-only. Examples: 'GET', 'DELETE'.

request.rawHeaders#
  • Type: {HTTP/2 Raw Headers}

The raw request/response headers list exactly as they were received.

// Prints something like:
//
// [ 'user-agent',
//   'this is invalid because there can be only one',
//   'User-Agent',
//   'curl/7.22.0',
//   'Host',
//   '127.0.0.1:8000',
//   'ACCEPT',
//   '*/*' ]
console.log(request.rawHeaders);
js
request.rawTrailers#

The raw request/response trailer keys and values exactly as they were received. Only populated at the 'end' event.

request.scheme#

The request scheme pseudo header field indicating the scheme portion of the target URL.

request.setTimeout(msecs, callback)#

Sets the Http2Stream's timeout value to msecs. If a callback is provided, then it is added as a listener on the 'timeout' event on the response object.

If no 'timeout' listener is added to the request, the response, or the server, then Http2Streams are destroyed when they time out. If a handler is assigned to the request, the response, or the server's 'timeout' events, timed out sockets must be handled explicitly.

request.socket#

Returns a Proxy object that acts as a net.Socket (or tls.TLSSocket) but applies getters, setters, and methods based on HTTP/2 logic.

destroyed, readable, and writable properties will be retrieved from and set on request.stream.

destroy, emit, end, on and once methods will be called on request.stream.

setTimeout method will be called on request.stream.session.

pause, read, resume, and write will throw an error with code ERR_HTTP2_NO_SOCKET_MANIPULATION. See Http2Session and Sockets for more information.

All other interactions will be routed directly to the socket. With TLS support, use request.socket.getPeerCertificate() to obtain the client's authentication details.

request.stream#

The Http2Stream object backing the request.

request.trailers#

The request/response trailers object. Only populated at the 'end' event.

request.url#

Request URL string. This contains only the URL that is present in the actual HTTP request. If the request is:

GET /status?name=ryan HTTP/1.1
Accept: text/plain
http

Then request.url will be:

"/status?name=ryan"
json

To parse the url into its parts, new URL() can be used:

$ node
> new URL('/status?name=ryan', 'http://example.com')
URL {
  href: 'http://example.com/status?name=ryan',
  origin: 'http://example.com',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'example.com',
  hostname: 'example.com',
  port: '',
  pathname: '/status',
  search: '?name=ryan',
  searchParams: URLSearchParams { 'name' => 'ryan' },
  hash: ''
}
console

Class: http2.Http2ServerResponse#

This object is created internally by an HTTP server, not by the user. It is passed as the second parameter to the 'request' event.

Event: 'close'#

Indicates that the underlying Http2Stream was terminated before response.end() was called or able to flush.

Event: 'finish'#

Emitted when the response has been sent. More specifically, this event is emitted when the last segment of the response headers and body have been handed off to the HTTP/2 multiplexing for transmission over the network. It does not imply that the client has received anything yet.

After this event, no more events will be emitted on the response object.

response.addTrailers(headers)#

This method adds HTTP trailing headers (a header but at the end of the message) to the response.

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

response.appendHeader(name, value)#

Append a single header value to the header object.

If the value is an array, this is equivalent to calling this method multiple times.

If there were no previous values for the header, this is equivalent to calling response.setHeader().

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

// Returns headers including "set-cookie: a" and "set-cookie: b"
const server = http2.createServer((req, res) => {
  res.setHeader('set-cookie', 'a');
  res.appendHeader('set-cookie', 'b');
  res.writeHead(200);
  res.end('ok');
});
js
response.connection#

Stability: 0 - Deprecated. Use response.socket.

See response.socket.

response.createPushResponse(headers, callback)#
  • headers <HTTP/2 Headers Object> An object describing the headers
  • callback <Function> Called once http2stream.pushStream() is finished, or either when the attempt to create the pushed Http2Stream has failed or has been rejected, or the state of Http2ServerRequest is closed prior to calling the http2stream.pushStream() method

Call http2stream.pushStream() with the given headers, and wrap the given Http2Stream on a newly created Http2ServerResponse as the callback parameter if successful. When Http2ServerRequest is closed, the callback is called with an error ERR_HTTP2_INVALID_STREAM.

response.end([data[, encoding]][, callback])#

This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete. The method, response.end(), MUST be called on each response.

If data is specified, it is equivalent to calling response.write(data, encoding) followed by response.end(callback).

If callback is specified, it will be called when the response stream is finished.

response.finished#

Stability: 0 - Deprecated. Use response.writableEnded.

Boolean value that indicates whether the response has completed. Starts as false. After response.end() executes, the value will be true.

response.getHeader(name)#

Reads out a header that has already been queued but not sent to the client. The name is case-insensitive.

const contentType = response.getHeader('content-type');
js
response.getHeaderNames()#

Returns an array containing the unique names of the current outgoing headers. All header names are lowercase.

response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headerNames = response.getHeaderNames();
// headerNames === ['foo', 'set-cookie']
js
response.getHeaders()#

Returns a shallow copy of the current outgoing headers. Since a shallow copy is used, array values may be mutated without additional calls to various header-related http module methods. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.

The object returned by the response.getHeaders() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work.

response.setHeader('Foo', 'bar');
response.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']);

const headers = response.getHeaders();
// headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] }
js
response.hasHeader(name)#

Returns true if the header identified by name is currently set in the outgoing headers. The header name matching is case-insensitive.

const hasContentType = response.hasHeader('content-type');
js
response.headersSent#

True if headers were sent, false otherwise (read-only).

response.removeHeader(name)#

Removes a header that has been queued for implicit sending.

response.removeHeader('Content-Encoding');
js
response.req#

A reference to the original HTTP2 request object.

response.sendDate#

When true, the Date header will be automatically generated and sent in the response if it is not already present in the headers. Defaults to true.

This should only be disabled for testing; HTTP requires the Date header in responses.

response.setHeader(name, value)#

Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name.

response.setHeader('Content-Type', 'text/html; charset=utf-8');
js

or

response.setHeader('Set-Cookie', ['type=ninja', 'language=javascript']);
js

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

When headers have been set with response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.

// Returns content-type = text/plain
const server = http2.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('ok');
});
js
response.setTimeout(msecs[, callback])#

Sets the Http2Stream's timeout value to msecs. If a callback is provided, then it is added as a listener on the 'timeout' event on the response object.

If no 'timeout' listener is added to the request, the response, or the server, then Http2Streams are destroyed when they time out. If a handler is assigned to the request, the response, or the server's 'timeout' events, timed out sockets must be handled explicitly.

response.socket#

Returns a Proxy object that acts as a net.Socket (or tls.TLSSocket) but applies getters, setters, and methods based on HTTP/2 logic.

destroyed, readable, and writable properties will be retrieved from and set on response.stream.

destroy, emit, end, on and once methods will be called on response.stream.

setTimeout method will be called on response.stream.session.

pause, read, resume, and write will throw an error with code ERR_HTTP2_NO_SOCKET_MANIPULATION. See Http2Session and Sockets for more information.

All other interactions will be routed directly to the socket.

import { createServer } from 'node:http2';
const server = createServer((req, res) => {
  const ip = req.socket.remoteAddress;
  const port = req.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);
const http2 = require('node:http2');
const server = http2.createServer((req, res) => {
  const ip = req.socket.remoteAddress;
  const port = req.socket.remotePort;
  res.end(`Your IP address is ${ip} and your source port is ${port}.`);
}).listen(3000);
javascript
response.statusCode#

When using implicit headers (not calling response.writeHead() explicitly), this property controls the status code that will be sent to the client when the headers get flushed.

response.statusCode = 404;
js

After response header was sent to the client, this property indicates the status code which was sent out.

response.statusMessage#

Status message is not supported by HTTP/2 (RFC 7540 8.1.2.4). It returns an empty string.

response.stream#

The Http2Stream object backing the response.

response.writableEnded#

Is true after response.end() has been called. This property does not indicate whether the data has been flushed, for this use writable.writableFinished instead.

response.write(chunk[, encoding][, callback])#

If this method is called and response.writeHead() has not been called, it will switch to implicit header mode and flush the implicit headers.

This sends a chunk of the response body. This method may be called multiple times to provide successive parts of the body.

In the node:http module, the response body is omitted when the request is a HEAD request. Similarly, the 204 and 304 responses must not include a message body.

chunk can be a string or a buffer. If chunk is a string, the second parameter specifies how to encode it into a byte stream. By default the encoding is 'utf8'. callback will be called when this chunk of data is flushed.

This is the raw HTTP body and has nothing to do with higher-level multi-part body encodings that may be used.

The first time response.write() is called, it will send the buffered header information and the first chunk of the body to the client. The second time response.write() is called, Node.js assumes data will be streamed, and sends the new data separately. That is, the response is buffered up to the first chunk of the body.

Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is free again.

response.writeContinue()#

Sends a status 100 Continue to the client, indicating that the request body should be sent. See the 'checkContinue' event on Http2Server and Http2SecureServer.

response.writeEarlyHints(hints)#

Sends a status 103 Early Hints to the client with a Link header, indicating that the user agent can preload/preconnect the linked resources. The hints is an object containing the values of headers to be sent with early hints message.

Example

const earlyHintsLink = '</styles.css>; rel=preload; as=style';
response.writeEarlyHints({
  'link': earlyHintsLink,
});

const earlyHintsLinks = [
  '</styles.css>; rel=preload; as=style',
  '</scripts.js>; rel=preload; as=script',
];
response.writeEarlyHints({
  'link': earlyHintsLinks,
});
js
response.writeInformation(statusCode[, headers])#
  • statusCode <number> An HTTP 1xx informational status code, between 100 and 199 inclusive, excluding 101 (Switching Protocols) which is not allowed in HTTP/2.
  • headers <Object> An optional object of headers to send with the informational response.

Sends an arbitrary HTTP 1xx informational response, equivalent in HTTP/2 to a HEADERS frame whose :status pseudo-header is a 1xx code. May be called multiple times before the final response. After the final response headers have been sent, this method is a no-op and returns false.

This is the generic equivalent of response.writeContinue() and response.writeEarlyHints().

response.writeInformation(110, { 'X-Progress': '50%' });
js
response.writeHead(statusCode[, statusMessage][, headers])#

Sends a response header to the request. The status code is a 3-digit HTTP status code, like 404. The last argument, headers, are the response headers.

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

For compatibility with HTTP/1, a human-readable statusMessage may be passed as the second argument. However, because the statusMessage has no meaning within HTTP/2, the argument will have no effect and a process warning will be emitted.

const body = 'hello world';
response.writeHead(200, {
  'Content-Length': Buffer.byteLength(body),
  'Content-Type': 'text/plain; charset=utf-8',
});
js

Content-Length is given in bytes not characters. The Buffer.byteLength() API may be used to determine the number of bytes in a given encoding. On outbound messages, Node.js does not check if Content-Length and the length of the body being transmitted are equal or not. However, when receiving messages, Node.js will automatically reject messages when the Content-Length does not match the actual payload size.

This method may be called at most one time on a message before response.end() is called.

If response.write() or response.end() are called before calling this, the implicit/mutable headers will be calculated and call this function.

When headers have been set with response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.

// Returns content-type = text/plain
const server = http2.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('ok');
});
js

Attempting to set a header field name or value that contains invalid characters will result in a TypeError being thrown.

Collecting HTTP/2 performance metrics#

The Performance Observer API can be used to collect basic performance metrics for each Http2Session and Http2Stream instance.

import { PerformanceObserver } from 'node:perf_hooks';

const obs = new PerformanceObserver((items) => {
  const entry = items.getEntries()[0];
  console.log(entry.entryType);  // prints 'http2'
  if (entry.name === 'Http2Session') {
    // Entry contains statistics about the Http2Session
  } else if (entry.name === 'Http2Stream') {
    // Entry contains statistics about the Http2Stream
  }
});
obs.observe({ entryTypes: ['http2'] });
const { PerformanceObserver } = require('node:perf_hooks');

const obs = new PerformanceObserver((items) => {
  const entry = items.getEntries()[0];
  console.log(entry.entryType);  // prints 'http2'
  if (entry.name === 'Http2Session') {
    // Entry contains statistics about the Http2Session
  } else if (entry.name === 'Http2Stream') {
    // Entry contains statistics about the Http2Stream
  }
});
obs.observe({ entryTypes: ['http2'] });
javascript

The entryType property of the PerformanceEntry will be equal to 'http2'.

The name property of the PerformanceEntry will be equal to either 'Http2Stream' or 'Http2Session'.

If name is equal to Http2Stream, the PerformanceEntry will contain the following additional properties:

  • bytesRead <number> The number of DATA frame bytes received for this Http2Stream.
  • bytesWritten <number> The number of DATA frame bytes sent for this Http2Stream.
  • id <number> The identifier of the associated Http2Stream
  • timeToFirstByte <number> The number of milliseconds elapsed between the PerformanceEntry startTime and the reception of the first DATA frame.
  • timeToFirstByteSent <number> The number of milliseconds elapsed between the PerformanceEntry startTime and sending of the first DATA frame.
  • timeToFirstHeader <number> The number of milliseconds elapsed between the PerformanceEntry startTime and the reception of the first header.

If name is equal to Http2Session, the PerformanceEntry will contain the following additional properties:

  • bytesRead <number> The number of bytes received for this Http2Session.
  • bytesWritten <number> The number of bytes sent for this Http2Session.
  • framesReceived <number> The number of HTTP/2 frames received by the Http2Session.
  • framesSent <number> The number of HTTP/2 frames sent by the Http2Session.
  • maxConcurrentStreams <number> The maximum number of streams concurrently open during the lifetime of the Http2Session.
  • pingRTT <number> The number of milliseconds elapsed since the transmission of a PING frame and the reception of its acknowledgment. Only present if a PING frame has been sent on the Http2Session.
  • streamAverageDuration <number> The average duration (in milliseconds) for all Http2Stream instances.
  • streamCount <number> The number of Http2Stream instances processed by the Http2Session.
  • type <string> Either 'server' or 'client' to identify the type of Http2Session.

Note on :authority and host#

HTTP/2 requires requests to have either the :authority pseudo-header or the host header. Prefer :authority when constructing an HTTP/2 request directly, and host when converting from HTTP/1 (in proxies, for instance).

The compatibility API falls back to host if :authority is not present. See request.authority for more information. However, if you don't use the compatibility API (or use req.headers directly), you need to implement any fall-back behavior yourself.

HTTPS#

Stability: 2 - Stable

HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module.

Determining if crypto support is unavailable#

It is possible for Node.js to be built without including support for the node:crypto module. In such cases, attempting to import from https or calling require('node:https') will result in an error being thrown.

When using CommonJS, the error thrown can be caught using try/catch:

let https;
try {
  https = require('node:https');
} catch (err) {
  console.error('https support is disabled!');
}
cjs

When using the lexical ESM import keyword, the error can only be caught if a handler for process.on('uncaughtException') is registered before any attempt to load the module is made (using, for instance, a preload module).

When using ESM, if there is a chance that the code may be run on a build of Node.js where crypto support is not enabled, consider using the import() function instead of the lexical import keyword:

let https;
try {
  https = await import('node:https');
} catch (err) {
  console.error('https support is disabled!');
}
mjs

Class: https.Agent#

An Agent object for HTTPS similar to http.Agent. See https.request() for more information.

Like http.Agent, the createConnection(options[, callback]) method can be overridden to customize how TLS connections are established.

See agent.createConnection() for details on overriding this method, including asynchronous socket creation with a callback.

new Agent([options])#

  • options <Object> Set of configurable options to set on the agent. Can have the same fields as for http.Agent(options), and
    • maxCachedSessions <number> maximum number of TLS cached sessions. Use 0 to disable TLS session caching. Default: 100.

    • servername <string> the value of Server Name Indication extension to be sent to the server. Use empty string '' to disable sending the extension. Default: host name of the target server, unless the target server is specified using an IP address, in which case the default is '' (no extension).

      See Session Resumption for information about TLS session reuse.

Event: 'keylog'#
  • line <Buffer> Line of ASCII text, in NSS SSLKEYLOGFILE format.
  • tlsSocket <tls.TLSSocket> The tls.TLSSocket instance on which it was generated.

The keylog event is emitted when key material is generated or received by a connection managed by this agent (typically before handshake has completed, but not necessarily). This keying material can be stored for debugging, as it allows captured TLS traffic to be decrypted. It may be emitted multiple times for each socket.

A typical use case is to append received lines to a common text file, which is later used by software (such as Wireshark) to decrypt the traffic:

// ...
https.globalAgent.on('keylog', (line, tlsSocket) => {
  fs.appendFileSync('/tmp/ssl-keys.log', line, { mode: 0o600 });
});
js

Class: https.Server#

See http.Server for more information.

server.close([callback])#

See server.close() in the node:http module.

server[Symbol.asyncDispose]()#

Calls server.close() and returns a promise that fulfills when the server has closed.

server.closeAllConnections()#

See server.closeAllConnections() in the node:http module.

server.closeIdleConnections()#

See server.closeIdleConnections() in the node:http module.

server.headersTimeout#

See server.headersTimeout in the node:http module.

server.listen()#

Starts the HTTPS server listening for encrypted connections. This method is identical to server.listen() from net.Server.

server.maxHeadersCount#

See server.maxHeadersCount in the node:http module.

server.requestTimeout#

See server.requestTimeout in the node:http module.

server.setTimeout([msecs][, callback])#

See server.setTimeout() in the node:http module.

server.timeout#

  • Type: <number> Default: 0 (no timeout)

See server.timeout in the node:http module.

server.keepAliveTimeout#

  • Type: <number> Default: 5000 (5 seconds)

See server.keepAliveTimeout in the node:http module.

https.createServer([options][, requestListener])#

// curl -k https://localhost:8000/
import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem'),
};

createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);
// curl -k https://localhost:8000/
const https = require('node:https');
const fs = require('node:fs');

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);
javascript

Or

import { createServer } from 'node:https';
import { readFileSync } from 'node:fs';

const options = {
  pfx: readFileSync('test_cert.pfx'),
  passphrase: 'sample',
};

createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);
const https = require('node:https');
const fs = require('node:fs');

const options = {
  pfx: fs.readFileSync('test_cert.pfx'),
  passphrase: 'sample',
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);
javascript

To generate the certificate and key for this example, run:

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
  -keyout private-key.pem -out certificate.pem
bash

Then, to generate the pfx certificate for this example, run:

openssl pkcs12 -certpbe AES-256-CBC -export -out test_cert.pfx \
  -inkey private-key.pem -in certificate.pem -passout pass:sample
bash

https.get(options[, callback])#

https.get(url[, options][, callback])#

Like http.get() but for HTTPS.

options can be an object, a string, or a URL object. If options is a string, it is automatically parsed with new URL(). If it is a URL object, it will be automatically converted to an ordinary options object.

import { get } from 'node:https';
import process from 'node:process';

get('https://encrypted.google.com/', (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});
const https = require('node:https');

https.get('https://encrypted.google.com/', (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});
javascript

https.globalAgent#

Global instance of https.Agent for all HTTPS client requests. Diverges from a default https.Agent configuration by having keepAlive enabled and a timeout of 5 seconds.

https.request(options[, callback])#

https.request(url[, options][, callback])#

Makes a request to a secure web server.

The following additional options from tls.connect() are also accepted: ca, cert, ciphers, clientCertEngine (deprecated), crl, dhparam, ecdhCurve, honorCipherOrder, key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext, highWaterMark.

options can be an object, a string, or a URL object. If options is a string, it is automatically parsed with new URL(). If it is a URL object, it will be automatically converted to an ordinary options object.

https.request() returns an instance of the http.ClientRequest class. The ClientRequest instance is a writable stream. If one needs to upload a file with a POST request, then write to the ClientRequest object.

import { request } from 'node:https';
import process from 'node:process';

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
};

const req = request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});
req.end();
const https = require('node:https');

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
};

const req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});
req.end();
javascript

Example using options from tls.connect():

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
};
options.agent = new https.Agent(options);

const req = https.request(options, (res) => {
  // ...
});
js

Alternatively, opt out of connection pooling by not using an Agent.

const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  agent: false,
};

const req = https.request(options, (res) => {
  // ...
});
js

Example using a URL as options:

const options = new URL('https://abc:xyz@example.com');

const req = https.request(options, (res) => {
  // ...
});
js

Example pinning on certificate fingerprint, or the public key (similar to pin-sha256):

import { checkServerIdentity } from 'node:tls';
import { Agent, request } from 'node:https';
import { createHash } from 'node:crypto';

function sha256(s) {
  return createHash('sha256').update(s).digest('base64');
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function(host, cert) {
    // Make sure the certificate is issued to the host we are connected to
    const err = checkServerIdentity(host, cert);
    if (err) {
      return err;
    }

    // Pin the public key, similar to HPKP pin-sha256 pinning
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=';
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg = 'Certificate verification error: ' +
        `The public key of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // Pin the exact certificate, rather than the pub key
    const cert256 = 'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' +
      '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65';
    if (cert.fingerprint256 !== cert256) {
      const msg = 'Certificate verification error: ' +
        `The certificate of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // This loop is informational only.
    // Print the certificate and public key fingerprints of all certs in the
    // chain. Its common to pin the public key of the issuer on the public
    // internet, while pinning the public key of the service in sensitive
    // environments.
    let lastprint256;
    do {
      console.log('Subject Common Name:', cert.subject.CN);
      console.log('  Certificate SHA256 fingerprint:', cert.fingerprint256);

      const hash = createHash('sha256');
      console.log('  Public key ping-sha256:', sha256(cert.pubkey));

      lastprint256 = cert.fingerprint256;
      cert = cert.issuerCertificate;
    } while (cert.fingerprint256 !== lastprint256);

  },
};

options.agent = new Agent(options);
const req = request(options, (res) => {
  console.log('All OK. Server matched our pinned cert or public key');
  console.log('statusCode:', res.statusCode);

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

req.on('error', (e) => {
  console.error(e.message);
});
req.end();
const tls = require('node:tls');
const https = require('node:https');
const crypto = require('node:crypto');

function sha256(s) {
  return crypto.createHash('sha256').update(s).digest('base64');
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function(host, cert) {
    // Make sure the certificate is issued to the host we are connected to
    const err = tls.checkServerIdentity(host, cert);
    if (err) {
      return err;
    }

    // Pin the public key, similar to HPKP pin-sha256 pinning
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=';
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg = 'Certificate verification error: ' +
        `The public key of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // Pin the exact certificate, rather than the pub key
    const cert256 = 'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' +
      '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65';
    if (cert.fingerprint256 !== cert256) {
      const msg = 'Certificate verification error: ' +
        `The certificate of '${cert.subject.CN}' ` +
        'does not match our pinned fingerprint';
      return new Error(msg);
    }

    // This loop is informational only.
    // Print the certificate and public key fingerprints of all certs in the
    // chain. Its common to pin the public key of the issuer on the public
    // internet, while pinning the public key of the service in sensitive
    // environments.
    do {
      console.log('Subject Common Name:', cert.subject.CN);
      console.log('  Certificate SHA256 fingerprint:', cert.fingerprint256);

      hash = crypto.createHash('sha256');
      console.log('  Public key ping-sha256:', sha256(cert.pubkey));

      lastprint256 = cert.fingerprint256;
      cert = cert.issuerCertificate;
    } while (cert.fingerprint256 !== lastprint256);

  },
};

options.agent = new https.Agent(options);
const req = https.request(options, (res) => {
  console.log('All OK. Server matched our pinned cert or public key');
  console.log('statusCode:', res.statusCode);

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

req.on('error', (e) => {
  console.error(e.message);
});
req.end();
javascript

Outputs for example:

Subject Common Name: github.com
  Certificate SHA256 fingerprint: FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65
  Public key ping-sha256: SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=
Subject Common Name: Sectigo ECC Domain Validation Secure Server CA
  Certificate SHA256 fingerprint: 61:E9:73:75:E9:F6:DA:98:2F:F5:C1:9E:2F:94:E6:6C:4E:35:B6:83:7C:E3:B9:14:D2:24:5C:7F:5F:65:82:5F
  Public key ping-sha256: Eep0p/AsSa9lFUH6KT2UY+9s1Z8v7voAPkQ4fGknZ2g=
Subject Common Name: USERTrust ECC Certification Authority
  Certificate SHA256 fingerprint: A6:CF:64:DB:B4:C8:D5:FD:19:CE:48:89:60:68:DB:03:B5:33:A8:D1:33:6C:62:56:A8:7D:00:CB:B3:DE:F3:EA
  Public key ping-sha256: UJM2FOhG9aTNY0Pg4hgqjNzZ/lQBiMGRxPD5Y2/e0bw=
Subject Common Name: AAA Certificate Services
  Certificate SHA256 fingerprint: D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4
  Public key ping-sha256: vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=
All OK. Server matched our pinned cert or public key
statusCode: 200
text

Inspector#

Stability: 2 - Stable

The node:inspector module provides an API for interacting with the V8 inspector.

It can be accessed using:

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

or

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

Promises API#

Stability: 1 - Experimental

Class: inspector.Session#

The inspector.Session is used for dispatching messages to the V8 inspector back-end and receiving message responses and notifications.

new inspector.Session()#

Create a new instance of the inspector.Session class. The inspector session needs to be connected through session.connect() before the messages can be dispatched to the inspector backend.

When using Session, the object outputted by the console API will not be released, unless we performed manually Runtime.DiscardConsoleEntries command.

Event: 'inspectorNotification'#
  • Type: <Object> The notification message object

Emitted when any notification from the V8 Inspector is received.

session.on('inspectorNotification', (message) => console.log(message.method));
// Debugger.paused
// Debugger.resumed
js

Caveat Breakpoints with same-thread session is not recommended, see support of breakpoints.

It is also possible to subscribe only to notifications with specific method:

Event: <inspector-protocol-method>#
  • Type: <Object> The notification message object

Emitted when an inspector notification is received that has its method field set to the <inspector-protocol-method> value.

The following snippet installs a listener on the 'Debugger.paused' event, and prints the reason for program suspension whenever program execution is suspended (through breakpoints, for example):

session.on('Debugger.paused', ({ params }) => {
  console.log(params.hitBreakpoints);
});
// [ '/the/file/that/has/the/breakpoint.js:11:0' ]
js

Caveat Breakpoints with same-thread session is not recommended, see support of breakpoints.

session.connect()#

Connects a session to the inspector back-end.

session.connectToMainThread()#

Connects a session to the main thread inspector back-end. An exception will be thrown if this API was not called on a Worker thread.

session.disconnect()#

Immediately close the session. All pending message callbacks will be called with an error. session.connect() will need to be called to be able to send messages again. Reconnected session will lose all inspector state, such as enabled agents or configured breakpoints.

session.post(method[, params])#

Posts a message to the inspector back-end.

import { Session } from 'node:inspector/promises';
try {
  const session = new Session();
  session.connect();
  const result = await session.post('Runtime.evaluate', { expression: '2 + 2' });
  console.log(result);
} catch (error) {
  console.error(error);
}
// Output: { result: { type: 'number', value: 4, description: '4' } }
mjs

The latest version of the V8 inspector protocol is published on the Chrome DevTools Protocol Viewer.

Node.js inspector supports all the Chrome DevTools Protocol domains declared by V8. Chrome DevTools Protocol domain provides an interface for interacting with one of the runtime agents used to inspect the application state and listen to the run-time events.

Example usage#

Apart from the debugger, various V8 Profilers are available through the DevTools protocol.

CPU profiler#

Here's an example showing how to use the CPU Profiler:

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';
const session = new Session();
session.connect();

await session.post('Profiler.enable');
await session.post('Profiler.start');
// Invoke business logic under measurement here...

// some time later...
const { profile } = await session.post('Profiler.stop');

// Write profile to disk, upload, etc.
fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));
mjs
Heap profiler#

Here's an example showing how to use the Heap Profiler:

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';
const session = new Session();

const fd = fs.openSync('profile.heapsnapshot', 'w');

session.connect();

session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
  fs.writeSync(fd, m.params.chunk);
});

const result = await session.post('HeapProfiler.takeHeapSnapshot', null);
console.log('HeapProfiler.takeHeapSnapshot done:', result);
session.disconnect();
fs.closeSync(fd);
mjs

Callback API#

Class: inspector.Session#

The inspector.Session is used for dispatching messages to the V8 inspector back-end and receiving message responses and notifications.

new inspector.Session()#

Create a new instance of the inspector.Session class. The inspector session needs to be connected through session.connect() before the messages can be dispatched to the inspector backend.

When using Session, the object outputted by the console API will not be released, unless we performed manually Runtime.DiscardConsoleEntries command.

Event: 'inspectorNotification'#
  • Type: <Object> The notification message object

Emitted when any notification from the V8 Inspector is received.

session.on('inspectorNotification', (message) => console.log(message.method));
// Debugger.paused
// Debugger.resumed
js

Caveat Breakpoints with same-thread session is not recommended, see support of breakpoints.

It is also possible to subscribe only to notifications with specific method:

Event: <inspector-protocol-method>;#
  • Type: <Object> The notification message object

Emitted when an inspector notification is received that has its method field set to the <inspector-protocol-method> value.

The following snippet installs a listener on the 'Debugger.paused' event, and prints the reason for program suspension whenever program execution is suspended (through breakpoints, for example):

session.on('Debugger.paused', ({ params }) => {
  console.log(params.hitBreakpoints);
});
// [ '/the/file/that/has/the/breakpoint.js:11:0' ]
js

Caveat Breakpoints with same-thread session is not recommended, see support of breakpoints.

session.connect()#

Connects a session to the inspector back-end.

session.connectToMainThread()#

Connects a session to the main thread inspector back-end. An exception will be thrown if this API was not called on a Worker thread.

session.disconnect()#

Immediately close the session. All pending message callbacks will be called with an error. session.connect() will need to be called to be able to send messages again. Reconnected session will lose all inspector state, such as enabled agents or configured breakpoints.

session.post(method[, params][, callback])#

Posts a message to the inspector back-end. callback will be notified when a response is received. callback is a function that accepts two optional arguments: error and message-specific result.

session.post('Runtime.evaluate', { expression: '2 + 2' },
             (error, { result }) => console.log(result));
// Output: { type: 'number', value: 4, description: '4' }
js

The latest version of the V8 inspector protocol is published on the Chrome DevTools Protocol Viewer.

Node.js inspector supports all the Chrome DevTools Protocol domains declared by V8. Chrome DevTools Protocol domain provides an interface for interacting with one of the runtime agents used to inspect the application state and listen to the run-time events.

You can not set reportProgress to true when sending a HeapProfiler.takeHeapSnapshot or HeapProfiler.stopTrackingHeapObjects command to V8.

Example usage#

Apart from the debugger, various V8 Profilers are available through the DevTools protocol.

CPU profiler#

Here's an example showing how to use the CPU Profiler:

const inspector = require('node:inspector');
const fs = require('node:fs');
const session = new inspector.Session();
session.connect();

session.post('Profiler.enable', () => {
  session.post('Profiler.start', () => {
    // Invoke business logic under measurement here...

    // some time later...
    session.post('Profiler.stop', (err, { profile }) => {
      // Write profile to disk, upload, etc.
      if (!err) {
        fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));
      }
    });
  });
});
js
Heap profiler#

Here's an example showing how to use the Heap Profiler:

const inspector = require('node:inspector');
const fs = require('node:fs');
const session = new inspector.Session();

const fd = fs.openSync('profile.heapsnapshot', 'w');

session.connect();

session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
  fs.writeSync(fd, m.params.chunk);
});

session.post('HeapProfiler.takeHeapSnapshot', null, (err, r) => {
  console.log('HeapProfiler.takeHeapSnapshot done:', err, r);
  session.disconnect();
  fs.closeSync(fd);
});
js

Common Objects#

inspector.close()#

Deactivates the inspector. If there are active connections, they are forcibly terminated. Blocks until the inspector server has fully stopped.

inspector.console#

  • Type: <Object> An object to send messages to the remote inspector console.
require('node:inspector').console.log('a message');
js

The inspector console does not have API parity with Node.js console.

inspector.open([port[, host[, wait]]])#

  • port <number> Port to listen on for inspector connections. Optional. Default: what was specified on the CLI.
  • host <string> Host to listen on for inspector connections. Optional. Default: what was specified on the CLI.
  • wait <boolean> Block until a client has connected. Optional. Default: false.
  • Returns: <Disposable> A Disposable that calls inspector.close().

Activate inspector on host and port. Equivalent to node --inspect=[[host:]port], but can be done programmatically after node has started.

If wait is true, will block until a client has connected to the inspect port and flow control has been passed to the debugger client.

See the security warning regarding the host parameter usage.

inspector.url()#

Return the URL of the active inspector, or undefined if there is none.

$ node --inspect -p 'inspector.url()'
Debugger listening on ws://127.0.0.1:9229/166e272e-7a30-4d09-97ce-f1c012b43c34
For help, see: https://nodejs.org/learn/getting-started/debugging
ws://127.0.0.1:9229/166e272e-7a30-4d09-97ce-f1c012b43c34

$ node --inspect=localhost:3000 -p 'inspector.url()'
Debugger listening on ws://localhost:3000/51cf8d0e-3c36-4c59-8efd-54519839e56a
For help, see: https://nodejs.org/learn/getting-started/debugging
ws://localhost:3000/51cf8d0e-3c36-4c59-8efd-54519839e56a

$ node -p 'inspector.url()'
undefined
console

inspector.waitForDebugger()#

Blocks until a client (existing or connected later) has sent Runtime.runIfWaitingForDebugger command.

An exception will be thrown if there is no active inspector.

Integration with DevTools#

Stability: 1.1 - Active development

The node:inspector module provides an API for integrating with devtools that support Chrome DevTools Protocol. DevTools frontends connected to a running Node.js instance can capture protocol events emitted from the instance and display them accordingly to facilitate debugging. The following methods broadcast a protocol event to all connected frontends. The params passed to the methods can be optional, depending on the protocol.

// The `Network.requestWillBeSent` event will be fired.
inspector.Network.requestWillBeSent({
  requestId: 'request-id-1',
  timestamp: Date.now() / 1000,
  wallTime: Date.now(),
  request: {
    url: 'https://nodejs.org/en',
    method: 'GET',
  },
});
js

inspector.Network.dataReceived([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.dataReceived event to connected frontends, or buffers the data if Network.streamResourceContent command was not invoked for the given request yet.

Also enables Network.getResponseBody command to retrieve the response data.

inspector.Network.dataSent([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Enables Network.getRequestPostData command to retrieve the request data.

inspector.Network.requestWillBeSent([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.requestWillBeSent event to connected frontends. This event indicates that the application is about to send an HTTP request.

inspector.Network.responseReceived([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.responseReceived event to connected frontends. This event indicates that HTTP response is available.

inspector.Network.loadingFinished([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.loadingFinished event to connected frontends. This event indicates that HTTP request has finished loading.

inspector.Network.loadingFailed([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.loadingFailed event to connected frontends. This event indicates that HTTP request has failed to load.

inspector.Network.webSocketCreated([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.webSocketCreated event to connected frontends. This event indicates that a WebSocket connection has been initiated.

inspector.Network.webSocketHandshakeResponseReceived([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.webSocketHandshakeResponseReceived event to connected frontends. This event indicates that the WebSocket handshake response has been received.

inspector.Network.webSocketClosed([params])#

This feature is only available with the --experimental-network-inspection flag enabled.

Broadcasts the Network.webSocketClosed event to connected frontends. This event indicates that a WebSocket connection has been closed.

inspector.NetworkResources.put#

Stability: 1.1 - Active Development

This feature is only available with the --experimental-inspector-network-resource flag enabled.

The inspector.NetworkResources.put method is used to provide a response for a loadNetworkResource request issued via the Chrome DevTools Protocol (CDP). This is typically triggered when a source map is specified by URL, and a DevTools frontend—such as Chrome—requests the resource to retrieve the source map.

This method allows developers to predefine the resource content to be served in response to such CDP requests.

const inspector = require('node:inspector');
// By preemptively calling put to register the resource, a source map can be resolved when
// a loadNetworkResource request is made from the frontend.
async function setNetworkResources() {
  const mapUrl = 'http://localhost:3000/dist/app.js.map';
  const tsUrl = 'http://localhost:3000/src/app.ts';
  const distAppJsMap = await fetch(mapUrl).then((res) => res.text());
  const srcAppTs = await fetch(tsUrl).then((res) => res.text());
  inspector.NetworkResources.put(mapUrl, distAppJsMap);
  inspector.NetworkResources.put(tsUrl, srcAppTs);
};
setNetworkResources().then(() => {
  require('./dist/app');
});
js

For more details, see the official CDP documentation: Network.loadNetworkResource

inspector.DOMStorage.domStorageItemAdded#

This feature is only available with the --experimental-storage-inspection flag enabled.

Broadcasts the DOMStorage.domStorageItemAdded event to connected frontends. This event indicates that a new item has been added to the storage.

inspector.DOMStorage.domStorageItemRemoved#

This feature is only available with the --experimental-storage-inspection flag enabled.

Broadcasts the DOMStorage.domStorageItemRemoved event to connected frontends. This event indicates that an item has been removed from the storage.

inspector.DOMStorage.domStorageItemUpdated#

This feature is only available with the --experimental-storage-inspection flag enabled.

Broadcasts the DOMStorage.domStorageItemUpdated event to connected frontends. This event indicates that a storage item has been updated.

inspector.DOMStorage.domStorageItemsCleared#

This feature is only available with the --experimental-storage-inspection flag enabled.

Broadcasts the DOMStorage.domStorageItemsCleared event to connected frontends. This event indicates that all items have been cleared from the storage.

inspector.DOMStorage.registerStorage#

This feature is only available with the --experimental-storage-inspection flag enabled.

Support of breakpoints#

The Chrome DevTools Protocol Debugger domain allows an inspector.Session to attach to a program and set breakpoints to step through the codes.

However, setting breakpoints with a same-thread inspector.Session, which is connected by session.connect(), should be avoided as the program being attached and paused is exactly the debugger itself. Instead, try connect to the main thread by session.connectToMainThread() and set breakpoints in a worker thread, or connect with a Debugger program over WebSocket connection.

Internationalization support#

Node.js has many features that make it easier to write internationalized programs. Some of them are:

Node.js and the underlying V8 engine use International Components for Unicode (ICU) to implement these features in native C/C++ code. The full ICU data set is provided by Node.js by default. However, due to the size of the ICU data file, several options are provided for customizing the ICU data set either when building or running Node.js.

Options for building Node.js#

To control how ICU is used in Node.js, four configure options are available during compilation. Additional details on how to compile Node.js are documented in BUILDING.md.

  • --with-intl=none/--without-intl
  • --with-intl=system-icu
  • --with-intl=small-icu
  • --with-intl=full-icu (default)

An overview of available Node.js and JavaScript features for each configure option:

Feature none system-icu small-icu full-icu
String.prototype.normalize() none (function is no-op) full full full
String.prototype.to*Case() full full full full
Intl none (object does not exist) partial/full (depends on OS) partial (English-only) full
String.prototype.localeCompare() partial (not locale-aware) full full full
String.prototype.toLocale*Case() partial (not locale-aware) full full full
Number.prototype.toLocaleString() partial (not locale-aware) partial/full (depends on OS) partial (English-only) full
Date.prototype.toLocale*String() partial (not locale-aware) partial/full (depends on OS) partial (English-only) full
Legacy URL Parser partial (no IDN support) full full full
WHATWG URL Parser partial (no IDN support) full full full
require('node:buffer').transcode() none (function does not exist) full full full
REPL partial (inaccurate line editing) full full full
require('node:util').TextDecoder partial (basic encodings support) partial/full (depends on OS) partial (Unicode-only) full
RegExp Unicode Property Escapes none (invalid RegExp error) full full full

The "(not locale-aware)" designation denotes that the function carries out its operation just like the non-Locale version of the function, if one exists. For example, under none mode, Date.prototype.toLocaleString()'s operation is identical to that of Date.prototype.toString().

Disable all internationalization features (none)#

If this option is chosen, ICU is disabled and most internationalization features mentioned above will be unavailable in the resulting node binary.

Build with a pre-installed ICU (system-icu)#

Node.js can link against an ICU build already installed on the system. In fact, most Linux distributions already come with ICU installed, and this option would make it possible to reuse the same set of data used by other components in the OS.

Functionalities that only require the ICU library itself, such as String.prototype.normalize() and the WHATWG URL parser, are fully supported under system-icu. Features that require ICU locale data in addition, such as Intl.DateTimeFormat may be fully or partially supported, depending on the completeness of the ICU data installed on the system.

Embed a limited set of ICU data (small-icu)#

This option makes the resulting binary link against the ICU library statically, and includes a subset of ICU data (typically only the English locale) within the node executable.

Functionalities that only require the ICU library itself, such as String.prototype.normalize() and the WHATWG URL parser, are fully supported under small-icu. Features that require ICU locale data in addition, such as Intl.DateTimeFormat, generally only work with the English locale:

const january = new Date(9e8);
const english = new Intl.DateTimeFormat('en', { month: 'long' });
const spanish = new Intl.DateTimeFormat('es', { month: 'long' });

console.log(english.format(january));
// Prints "January"
console.log(spanish.format(january));
// Prints either "M01" or "January" on small-icu, depending on the user’s default locale
// Should print "enero"
js

This mode provides a balance between features and binary size.

Providing ICU data at runtime#

If the small-icu option is used, one can still provide additional locale data at runtime so that the JS methods would work for all ICU locales. Assuming the data file is stored at /runtime/directory/with/dat/file, it can be made available to ICU through either:

  • The --with-icu-default-data-dir configure option:

    ./configure --with-icu-default-data-dir=/runtime/directory/with/dat/file --with-intl=small-icu
    
    bash

    This only embeds the default data directory path into the binary. The actual data file is going to be loaded at runtime from this directory path.

  • The NODE_ICU_DATA environment variable:

    env NODE_ICU_DATA=/runtime/directory/with/dat/file node
    
    bash
  • The --icu-data-dir CLI parameter:

    node --icu-data-dir=/runtime/directory/with/dat/file
    
    bash

When more than one of them is specified, the --icu-data-dir CLI parameter has the highest precedence, then the NODE_ICU_DATA environment variable, then the --with-icu-default-data-dir configure option.

ICU is able to automatically find and load a variety of data formats, but the data must be appropriate for the ICU version, and the file correctly named. The most common name for the data file is icudtX[bl].dat, where X denotes the intended ICU version, and b or l indicates the system's endianness. Node.js would fail to load if the expected data file cannot be read from the specified directory. The name of the data file corresponding to the current Node.js version can be computed with:

`icudt${process.versions.icu.split('.')[0]}${os.endianness()[0].toLowerCase()}.dat`;
js

Check "ICU Data" article in the ICU User Guide for other supported formats and more details on ICU data in general.

The full-icu npm module can greatly simplify ICU data installation by detecting the ICU version of the running node executable and downloading the appropriate data file. After installing the module through npm i full-icu, the data file will be available at ./node_modules/full-icu. This path can be then passed either to NODE_ICU_DATA or --icu-data-dir as shown above to enable full Intl support.

Embed the entire ICU (full-icu)#

This option makes the resulting binary link against ICU statically and include a full set of ICU data. A binary created this way has no further external dependencies and supports all locales, but might be rather large. This is the default behavior if no --with-intl flag is passed. The official binaries are also built in this mode.

Detecting internationalization support#

To verify that ICU is enabled at all (system-icu, small-icu, or full-icu), simply checking the existence of Intl should suffice:

const hasICU = typeof Intl === 'object';
js

Alternatively, checking for process.versions.icu, a property defined only when ICU is enabled, works too:

const hasICU = typeof process.versions.icu === 'string';
js

To check for support for a non-English locale (i.e. full-icu or system-icu), Intl.DateTimeFormat can be a good distinguishing factor:

const hasFullICU = (() => {
  try {
    const january = new Date(9e8);
    const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
    return spanish.format(january) === 'enero';
  } catch (err) {
    return false;
  }
})();
js

For more verbose tests for Intl support, the following resources may be found to be helpful:

  • btest402: Generally used to check whether Node.js with Intl support is built correctly.
  • Test262: ECMAScript's official conformance test suite includes a section dedicated to ECMA-402.

About this documentation#

Welcome to the official API reference documentation for Node.js!

Node.js is a JavaScript runtime built on the V8 JavaScript engine.

Contributing#

Report errors in this documentation in the issue tracker. See the contributing guide for directions on how to submit pull requests.

Stability index#

Throughout the documentation are indications of a section's stability. Some APIs are so proven and so relied upon that they are unlikely to ever change at all. Others are brand new and experimental, or known to be hazardous.

The stability indexes are as follows:

Stability: 0 - Deprecated. The feature may emit warnings. Backward compatibility is not guaranteed.

Stability: 1 - Experimental. The feature is not subject to semantic versioning rules. Non-backward compatible changes or removal may occur in any future release. Use of the feature is not recommended in production environments.

Experimental features are subdivided into stages:

  • 1.0 - Early development. Experimental features at this stage are unfinished and subject to substantial change.
  • 1.1 - Active development. Experimental features at this stage are nearing minimum viability.
  • 1.2 - Release candidate. Experimental features at this stage are hopefully ready to become stable. No further breaking changes are anticipated but may still occur in response to user feedback or the features' underlying specification development. We encourage user testing and feedback so that we can know that this feature is ready to be marked as stable.

Experimental features leave the experimental status typically either by graduating to stable, or are removed without a deprecation cycle.

Stability: 2 - Stable. Compatibility with the npm ecosystem is a high priority.

Stability: 3 - Legacy. Although this feature is unlikely to be removed and is still covered by semantic versioning guarantees, it is no longer actively maintained, and other alternatives are available.

Features are marked as legacy rather than being deprecated if their use does no harm, and they are widely relied upon within the npm ecosystem. Bugs found in legacy features are unlikely to be fixed.

Use caution when making use of Experimental features, particularly when authoring libraries. Users may not be aware that experimental features are being used. Bugs or behavior changes may surprise users when Experimental API modifications occur. To avoid surprises, use of an Experimental feature may need a command-line flag. Experimental features may also emit a warning.

Stability overview#

APIStability
Assert(2) Stable
Async hooks(1) Experimental
Asynchronous context tracking(2) Stable
Buffer(2) Stable
Child process(2) Stable
Cluster(2) Stable
Console(2) Stable
Crypto(2) Stable
Debugger(2) Stable
Diagnostic report(2) Stable
Diagnostics Channel(2) Stable
DNS(2) Stable
Domain(0) Deprecated
Events(2) Stable
FFI(1) Experimental
File system(2) Stable
Global objects(2) Stable
HTTP(2) Stable
HTTP/2(2) Stable
HTTPS(2) Stable
Inspector(2) Stable
Iterable Streams(1) Experimental
Modules: CommonJS modules(2) Stable
Modules: ECMAScript modules(2) Stable
Modules: TypeScript(2) Stable
Net(2) Stable
Node-API(2) Stable
OS(2) Stable
Path(2) Stable
Performance measurement APIs(2) Stable
Punycode(0) Deprecated
Query string(2) Stable
Readline(2) Stable
REPL(2) Stable
Single executable applications(1.1) Active development
SQLite(1.2) Release candidate.
Stream(2) Stable
String decoder(2) Stable
Test runner(2) Stable
Timers(2) Stable
TLS (SSL)(2) Stable
Trace events(1) Experimental
TTY(2) Stable
UDP/datagram sockets(2) Stable
URL(2) Stable
Util(2) Stable
Virtual File System(1) Experimental
VM (executing JavaScript)(2) Stable
Web Crypto API(2) Stable
Web Streams API(2) Stable
WebAssembly System Interface (WASI)(1) Experimental
Worker threads(2) Stable
Zlib(2) Stable

JSON output#

Every .html document has a corresponding .json document. This is for IDEs and other utilities that consume the documentation.

System calls and man pages#

Node.js functions which wrap a system call will document that. The docs link to the corresponding man pages which describe how the system call works.

Most Unix system calls have Windows analogues. Still, behavior differences may be unavoidable.

Assert#

Stability: 2 - Stable

The node:assert module provides a set of assertion functions for verifying invariants.

Strict assertion mode#

In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example, assert.deepEqual() will behave like assert.deepStrictEqual().

In strict assertion mode, error messages for objects display a diff. In legacy assertion mode, error messages for objects display the objects, often truncated.

Message parameter semantics#

For assertion methods that accept an optional message parameter, the message may be provided in one of the following forms:

  • string: Used as-is. If additional arguments are supplied after the message string, they are treated as printf-like substitutions (see util.format()).
  • Error: If an Error instance is provided as message, that error is thrown directly instead of an AssertionError.
  • function: A function of the form (actual, expected) => string. It is called only when the assertion fails and should return a string to be used as the error message. Non-string return values are ignored and the default message is used instead.

If additional arguments are passed along with an Error or a function as message, the call is rejected with ERR_AMBIGUOUS_ARGUMENT.

If the first item is neither a string, Error, nor function, ERR_INVALID_ARG_TYPE is thrown.

To use strict assertion mode:

import { strict as assert } from 'node:assert';
const assert = require('node:assert').strict;
javascript
import assert from 'node:assert/strict';
const assert = require('node:assert/strict');
javascript

Example error diff:

import { strict as assert } from 'node:assert';

assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
//   [
//     [
// ...
//       2,
// +     3
// -     '3'
//     ],
// ...
//     5
//   ]
const assert = require('node:assert/strict');

assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected ... Lines skipped
//
//   [
//     [
// ...
//       2,
// +     3
// -     '3'
//     ],
// ...
//     5
//   ]
javascript

To deactivate the colors, use the NO_COLOR or NODE_DISABLE_COLORS environment variables. This will also deactivate the colors in the REPL. For more on color support in terminal environments, read the tty getColorDepth() documentation.

Legacy assertion mode#

Legacy assertion mode uses the == operator in:

To use legacy assertion mode:

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

Legacy assertion mode may have surprising results, especially when using assert.deepEqual():

// WARNING: This does not throw an AssertionError in legacy assertion mode!
assert.deepEqual(/a/gi, new Date());
cjs

Class: assert.AssertionError#

Indicates the failure of an assertion. All errors thrown by the node:assert module will be instances of the AssertionError class.

new assert.AssertionError(options)#

  • options <Object>
    • message <string> If provided, the error message is set to this value.
    • actual <any> The actual property on the error instance.
    • expected <any> The expected property on the error instance.
    • operator <string> The operator property on the error instance.
    • stackStartFn <Function> If provided, the generated stack trace omits frames before this function.
    • diff <string> If set to 'full', shows the full diff in assertion errors. Defaults to 'simple'. Accepted values: 'simple', 'full'.

A subclass of <Error> that indicates the failure of an assertion.

All instances contain the built-in Error properties (message and name) and:

  • actual <any> Set to the actual argument for methods such as assert.strictEqual().
  • expected <any> Set to the expected value for methods such as assert.strictEqual().
  • generatedMessage <boolean> Indicates if the message was auto-generated (true) or not.
  • code <string> Value is always ERR_ASSERTION to show that the error is an assertion error.
  • operator <string> Set to the passed in operator value.
import assert from 'node:assert';

// Generate an AssertionError to compare the error message later:
const { message } = new assert.AssertionError({
  actual: 1,
  expected: 2,
  operator: 'strictEqual',
});

// Verify error output:
try {
  assert.strictEqual(1, 2);
} catch (err) {
  assert(err instanceof assert.AssertionError);
  assert.strictEqual(err.message, message);
  assert.strictEqual(err.name, 'AssertionError');
  assert.strictEqual(err.actual, 1);
  assert.strictEqual(err.expected, 2);
  assert.strictEqual(err.code, 'ERR_ASSERTION');
  assert.strictEqual(err.operator, 'strictEqual');
  assert.strictEqual(err.generatedMessage, true);
}
const assert = require('node:assert');

// Generate an AssertionError to compare the error message later:
const { message } = new assert.AssertionError({
  actual: 1,
  expected: 2,
  operator: 'strictEqual',
});

// Verify error output:
try {
  assert.strictEqual(1, 2);
} catch (err) {
  assert(err instanceof assert.AssertionError);
  assert.strictEqual(err.message, message);
  assert.strictEqual(err.name, 'AssertionError');
  assert.strictEqual(err.actual, 1);
  assert.strictEqual(err.expected, 2);
  assert.strictEqual(err.code, 'ERR_ASSERTION');
  assert.strictEqual(err.operator, 'strictEqual');
  assert.strictEqual(err.generatedMessage, true);
}
javascript

Class: assert.Assert#

The Assert class allows creating independent assertion instances with custom options.

new assert.Assert([options])#

  • options <Object>
    • diff <string> If set to 'full', shows the full diff in assertion errors. Defaults to 'simple'. Accepted values: 'simple', 'full'.
    • strict <boolean> If set to true, non-strict methods behave like their corresponding strict methods. Defaults to true.
    • skipPrototype <boolean> If set to true, skips prototype and constructor comparison in deep equality checks. Defaults to false.

Creates a new assertion instance. The diff option controls the verbosity of diffs in assertion error messages.

const { Assert } = require('node:assert');
const assertInstance = new Assert({ diff: 'full' });
assertInstance.deepStrictEqual({ a: 1 }, { a: 2 });
// Shows a full diff in the error message.
js

Important: When destructuring assertion methods from an Assert instance, the methods lose their connection to the instance's configuration options (such as diff, strict, and skipPrototype settings). The destructured methods will fall back to default behavior instead.

const myAssert = new Assert({ diff: 'full' });

// This works as expected - uses 'full' diff
myAssert.strictEqual({ a: 1 }, { b: { c: 1 } });

// This loses the 'full' diff setting - falls back to default 'simple' diff
const { strictEqual } = myAssert;
strictEqual({ a: 1 }, { b: { c: 1 } });
js

The skipPrototype option affects all deep equality methods:

class Foo {
  constructor(a) {
    this.a = a;
  }
}

class Bar {
  constructor(a) {
    this.a = a;
  }
}

const foo = new Foo(1);
const bar = new Bar(1);

// Default behavior - fails due to different constructors
const assert1 = new Assert();
assert1.deepStrictEqual(foo, bar); // AssertionError

// Skip prototype comparison - passes if properties are equal
const assert2 = new Assert({ skipPrototype: true });
assert2.deepStrictEqual(foo, bar); // OK
js

When destructured, methods lose access to the instance's this context and revert to default assertion behavior (diff: 'simple', non-strict mode). To maintain custom options when using destructured methods, avoid destructuring and call methods directly on the instance.

assert(value[, message])#

An alias of assert.ok().

assert.deepEqual(actual, expected[, message])#

Strict assertion mode

An alias of assert.deepStrictEqual().

Legacy assertion mode

Stability: 3 - Legacy: Use assert.deepStrictEqual() instead.

Tests for deep equality between the actual and expected parameters. Consider using assert.deepStrictEqual() instead. assert.deepEqual() can have surprising results.

Deep equality means that the enumerable "own" properties of child objects are also recursively evaluated by the following rules.

Comparison details#

  • Primitive values are compared with the == operator, with the exception of <NaN>. It is treated as being identical in case both sides are <NaN>.
  • Type tags of objects should be the same.
  • Only enumerable "own" properties are considered.
  • Object constructors are compared when available.
  • <Error> names, messages, causes, and errors are always compared, even if these are not enumerable properties.
  • Object wrappers are compared both as objects and unwrapped values.
  • Object properties are compared unordered.
  • <Map> keys and <Set> items are compared unordered.
  • Recursion stops when both sides differ or either side encounters a circular reference.
  • Implementation does not test the [[Prototype]] of objects.
  • <Symbol> properties are not compared.
  • <WeakMap>, <WeakSet> and <Promise> instances are not compared structurally. They are only equal if they reference the same object. Any comparison between different WeakMap, WeakSet, or Promise instances will result in inequality, even if they contain the same content.
  • <RegExp> lastIndex, flags, and source are always compared, even if these are not enumerable properties.

The following example does not throw an AssertionError because the primitives are compared using the == operator.

import assert from 'node:assert';
// WARNING: This does not throw an AssertionError!

assert.deepEqual('+00000000', false);
const assert = require('node:assert');
// WARNING: This does not throw an AssertionError!

assert.deepEqual('+00000000', false);
javascript

"Deep" equality means that the enumerable "own" properties of child objects are evaluated also:

import assert from 'node:assert';

const obj1 = {
  a: {
    b: 1,
  },
};
const obj2 = {
  a: {
    b: 2,
  },
};
const obj3 = {
  a: {
    b: 1,
  },
};
const obj4 = { __proto__: obj1 };

assert.deepEqual(obj1, obj1);
// OK

// Values of b are different:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }

assert.deepEqual(obj1, obj3);
// OK

// Prototypes are ignored:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
const assert = require('node:assert');

const obj1 = {
  a: {
    b: 1,
  },
};
const obj2 = {
  a: {
    b: 2,
  },
};
const obj3 = {
  a: {
    b: 1,
  },
};
const obj4 = { __proto__: obj1 };

assert.deepEqual(obj1, obj1);
// OK

// Values of b are different:
assert.deepEqual(obj1, obj2);
// AssertionError: { a: { b: 1 } } deepEqual { a: { b: 2 } }

assert.deepEqual(obj1, obj3);
// OK

// Prototypes are ignored:
assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
javascript

If the values are not equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.deepStrictEqual(actual, expected[, message])#

Tests for deep equality between the actual and expected parameters. "Deep" equality means that the enumerable "own" properties of child objects are recursively evaluated also by the following rules.

Comparison details#

  • Primitive values are compared using Object.is().
  • Type tags of objects should be the same.
  • [[Prototype]] of objects are compared using the === operator.
  • Only enumerable "own" properties are considered.
  • <Error> names, messages, causes, and errors are always compared, even if these are not enumerable properties. errors is also compared.
  • Enumerable own <Symbol> properties are compared as well.
  • Object wrappers are compared both as objects and unwrapped values.
  • Object properties are compared unordered.
  • <Map> keys and <Set> items are compared unordered.
  • Recursion stops when both sides differ or either side encounters a circular reference.
  • <WeakMap>, <WeakSet> and <Promise> instances are not compared structurally. They are only equal if they reference the same object. Any comparison between different WeakMap, WeakSet, or Promise instances will result in inequality, even if they contain the same content.
  • <RegExp> lastIndex, flags, and source are always compared, even if these are not enumerable properties.
import assert from 'node:assert/strict';

// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
//   {
// +   a: 1
// -   a: '1'
//   }

// The following objects don't have own properties
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);

// Different [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}

// Different type tags:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}

assert.deepStrictEqual(NaN, NaN);
// OK because Object.is(NaN, NaN) is true.

// Different unwrapped numbers:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]

assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK because the object and the string are identical when unwrapped.

assert.deepStrictEqual(-0, -0);
// OK

// Different zeros:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0

const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK, because it is the same symbol on both objects.

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
//   Symbol(): 1
// }

const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap();
const obj = {};

weakMap1.set(obj, 'value');
weakMap2.set(obj, 'value');

// Comparing different instances fails, even with same contents
assert.deepStrictEqual(weakMap1, weakMap2);
// AssertionError: Values have same structure but are not reference-equal:
//
// WeakMap {
//   <items unknown>
// }

// Comparing the same instance to itself succeeds
assert.deepStrictEqual(weakMap1, weakMap1);
// OK

const weakSet1 = new WeakSet();
const weakSet2 = new WeakSet();
weakSet1.add(obj);
weakSet2.add(obj);

// Comparing different instances fails, even with same contents
assert.deepStrictEqual(weakSet1, weakSet2);
// AssertionError: Values have same structure but are not reference-equal:
// + actual - expected
//
// WeakSet {
//   <items unknown>
// }

// Comparing the same instance to itself succeeds
assert.deepStrictEqual(weakSet1, weakSet1);
// OK
const assert = require('node:assert/strict');

// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
//   {
// +   a: 1
// -   a: '1'
//   }

// The following objects don't have own properties
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);

// Different [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}

// Different type tags:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}

assert.deepStrictEqual(NaN, NaN);
// OK because Object.is(NaN, NaN) is true.

// Different unwrapped numbers:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]

assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK because the object and the string are identical when unwrapped.

assert.deepStrictEqual(-0, -0);
// OK

// Different zeros:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0

const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK, because it is the same symbol on both objects.

assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
//   Symbol(): 1
// }

const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap();
const obj = {};

weakMap1.set(obj, 'value');
weakMap2.set(obj, 'value');

// Comparing different instances fails, even with same contents
assert.deepStrictEqual(weakMap1, weakMap2);
// AssertionError: Values have same structure but are not reference-equal:
//
// WeakMap {
//   <items unknown>
// }

// Comparing the same instance to itself succeeds
assert.deepStrictEqual(weakMap1, weakMap1);
// OK

const weakSet1 = new WeakSet();
const weakSet2 = new WeakSet();
weakSet1.add(obj);
weakSet2.add(obj);

// Comparing different instances fails, even with same contents
assert.deepStrictEqual(weakSet1, weakSet2);
// AssertionError: Values have same structure but are not reference-equal:
// + actual - expected
//
// WeakSet {
//   <items unknown>
// }

// Comparing the same instance to itself succeeds
assert.deepStrictEqual(weakSet1, weakSet1);
// OK
javascript

If the values are not equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.doesNotMatch(string, regexp[, message])#

Expects the string input not to match the regular expression.

import assert from 'node:assert/strict';

assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...

assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.doesNotMatch('I will pass', /different/);
// OK
const assert = require('node:assert/strict');

assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...

assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.doesNotMatch('I will pass', /different/);
// OK
javascript

If the values do match, or if the string argument is of another type than string, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.doesNotReject(asyncFn[, error][, message])#

Awaits the asyncFn promise or, if asyncFn is a function, immediately calls the function and awaits the returned promise to complete. It will then check that the promise is not rejected.

If asyncFn is a function and it throws an error synchronously, assert.doesNotReject() will return a rejected Promise with that error. If the function does not return a promise, assert.doesNotReject() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE error. In both cases the error handler is skipped.

Using assert.doesNotReject() is actually not useful because there is little benefit in catching a rejection and then rejecting it again. Instead, consider adding a comment next to the specific code path that should not reject and keep error messages as expressive as possible.

If specified, error can be a Class, <RegExp> or a validation function. See assert.throws() for more details.

Besides the async nature to await the completion behaves identically to assert.doesNotThrow().

import assert from 'node:assert/strict';

await assert.doesNotReject(
  async () => {
    throw new TypeError('Wrong value');
  },
  SyntaxError,
);
const assert = require('node:assert/strict');

(async () => {
  await assert.doesNotReject(
    async () => {
      throw new TypeError('Wrong value');
    },
    SyntaxError,
  );
})();
javascript
import assert from 'node:assert/strict';

assert.doesNotReject(Promise.reject(new TypeError('Wrong value')))
  .then(() => {
    // ...
  });
const assert = require('node:assert/strict');

assert.doesNotReject(Promise.reject(new TypeError('Wrong value')))
  .then(() => {
    // ...
  });
javascript

assert.doesNotThrow(fn[, error][, message])#

Asserts that the function fn does not throw an error.

Using assert.doesNotThrow() is actually not useful because there is no benefit in catching an error and then rethrowing it. Instead, consider adding a comment next to the specific code path that should not throw and keep error messages as expressive as possible.

When assert.doesNotThrow() is called, it will immediately call the fn function.

If an error is thrown and it is the same type as that specified by the error parameter, then an AssertionError is thrown. If the error is of a different type, or if the error parameter is undefined, the error is propagated back to the caller.

If specified, error can be a Class, <RegExp>, or a validation function. See assert.throws() for more details.

The following, for instance, will throw the <TypeError> because there is no matching error type in the assertion:

import assert from 'node:assert/strict';

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  SyntaxError,
);
const assert = require('node:assert/strict');

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  SyntaxError,
);
javascript

However, the following will result in an AssertionError with the message 'Got unwanted exception...':

import assert from 'node:assert/strict';

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  TypeError,
);
const assert = require('node:assert/strict');

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  TypeError,
);
javascript

If an AssertionError is thrown and a value is provided for the message parameter, the value of message will be appended to the AssertionError message:

import assert from 'node:assert/strict';

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  /Wrong value/,
  'Whoops',
);
// Throws: AssertionError: Got unwanted exception: Whoops
const assert = require('node:assert/strict');

assert.doesNotThrow(
  () => {
    throw new TypeError('Wrong value');
  },
  /Wrong value/,
  'Whoops',
);
// Throws: AssertionError: Got unwanted exception: Whoops
javascript

assert.equal(actual, expected[, message])#

Strict assertion mode

An alias of assert.strictEqual().

Legacy assertion mode

Stability: 3 - Legacy: Use assert.strictEqual() instead.

Tests shallow, coercive equality between the actual and expected parameters using the == operator. NaN is specially handled and treated as being identical if both sides are NaN.

import assert from 'node:assert';

assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(NaN, NaN);
// OK

assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
const assert = require('node:assert');

assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(NaN, NaN);
// OK

assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
javascript

If the values are not equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.fail([message])#

Throws an AssertionError with the provided error message or a default error message. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

import assert from 'node:assert/strict';

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail(new TypeError('need array'));
// TypeError: need array
const assert = require('node:assert/strict');

assert.fail();
// AssertionError [ERR_ASSERTION]: Failed

assert.fail('boom');
// AssertionError [ERR_ASSERTION]: boom

assert.fail(new TypeError('need array'));
// TypeError: need array
javascript

assert.ifError(value)#

Throws value if value is not undefined or null. This is useful when testing the error argument in callbacks. The stack trace contains all frames from the error passed to ifError() including the potential new frames for ifError() itself.

import assert from 'node:assert/strict';

assert.ifError(null);
// OK
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error

// Create some random error frames.
let err;
(function errorFrame() {
  err = new Error('test error');
})();

(function ifErrorFrame() {
  assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
//     at ifErrorFrame
//     at errorFrame
const assert = require('node:assert/strict');

assert.ifError(null);
// OK
assert.ifError(0);
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 0
assert.ifError('error');
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: 'error'
assert.ifError(new Error());
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: Error

// Create some random error frames.
let err;
(function errorFrame() {
  err = new Error('test error');
})();

(function ifErrorFrame() {
  assert.ifError(err);
})();
// AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
//     at ifErrorFrame
//     at errorFrame
javascript

assert.match(string, regexp[, message])#

Expects the string input to match the regular expression.

import assert from 'node:assert/strict';

assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...

assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.match('I will pass', /pass/);
// OK
const assert = require('node:assert/strict');

assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...

assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.match('I will pass', /pass/);
// OK
javascript

If the values do not match, or if the string argument is of another type than string, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.notDeepEqual(actual, expected[, message])#

Strict assertion mode

An alias of assert.notDeepStrictEqual().

Legacy assertion mode

Stability: 3 - Legacy: Use assert.notDeepStrictEqual() instead.

Tests for any deep inequality. Opposite of assert.deepEqual().

import assert from 'node:assert';

const obj1 = {
  a: {
    b: 1,
  },
};
const obj2 = {
  a: {
    b: 2,
  },
};
const obj3 = {
  a: {
    b: 1,
  },
};
const obj4 = { __proto__: obj1 };

assert.notDeepEqual(obj1, obj1);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj2);
// OK

assert.notDeepEqual(obj1, obj3);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj4);
// OK
const assert = require('node:assert');

const obj1 = {
  a: {
    b: 1,
  },
};
const obj2 = {
  a: {
    b: 2,
  },
};
const obj3 = {
  a: {
    b: 1,
  },
};
const obj4 = { __proto__: obj1 };

assert.notDeepEqual(obj1, obj1);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj2);
// OK

assert.notDeepEqual(obj1, obj3);
// AssertionError: { a: { b: 1 } } notDeepEqual { a: { b: 1 } }

assert.notDeepEqual(obj1, obj4);
// OK
javascript

If the values are deeply equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.notDeepStrictEqual(actual, expected[, message])#

Tests for deep strict inequality. Opposite of assert.deepStrictEqual().

import assert from 'node:assert/strict';

assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
const assert = require('node:assert/strict');

assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
javascript

If the values are deeply and strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.notEqual(actual, expected[, message])#

Strict assertion mode

An alias of assert.notStrictEqual().

Legacy assertion mode

Stability: 3 - Legacy: Use assert.notStrictEqual() instead.

Tests shallow, coercive inequality with the != operator. NaN is specially handled and treated as being identical if both sides are NaN.

import assert from 'node:assert';

assert.notEqual(1, 2);
// OK

assert.notEqual(1, 1);
// AssertionError: 1 != 1

assert.notEqual(1, '1');
// AssertionError: 1 != '1'
const assert = require('node:assert');

assert.notEqual(1, 2);
// OK

assert.notEqual(1, 1);
// AssertionError: 1 != 1

assert.notEqual(1, '1');
// AssertionError: 1 != '1'
javascript

If the values are equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.notStrictEqual(actual, expected[, message])#

Tests strict inequality between the actual and expected parameters as determined by Object.is().

import assert from 'node:assert/strict';

assert.notStrictEqual(1, 2);
// OK

assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1

assert.notStrictEqual(1, '1');
// OK
const assert = require('node:assert/strict');

assert.notStrictEqual(1, 2);
// OK

assert.notStrictEqual(1, 1);
// AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
//
// 1

assert.notStrictEqual(1, '1');
// OK
javascript

If the values are strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.ok(value[, message])#

Tests if value is truthy. It is equivalent to assert.equal(!!value, true, message).

If value is not truthy, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError. If no arguments are passed in at all message will be set to the string: 'No value argument passed to `assert.ok()`'.

Be aware that in the repl the error message will be different to the one thrown in a file! See below for further details.

import assert from 'node:assert/strict';

assert.ok(true);
// OK
assert.ok(1);
// OK

assert.ok();
// AssertionError: No value argument passed to `assert.ok()`

assert.ok(false, 'it\'s false');
// AssertionError: it's false

// In the repl:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true

// In a file (e.g. test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(typeof 123 === 'string')

assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(false)

assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(0)
const assert = require('node:assert/strict');

assert.ok(true);
// OK
assert.ok(1);
// OK

assert.ok();
// AssertionError: No value argument passed to `assert.ok()`

assert.ok(false, 'it\'s false');
// AssertionError: it's false

// In the repl:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true

// In a file (e.g. test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(typeof 123 === 'string')

assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(false)

assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert.ok(0)
javascript
import assert from 'node:assert/strict';

// Using `assert()` works the same:
assert(2 + 2 > 5);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert(2 + 2 > 5)
const assert = require('node:assert');

// Using `assert()` works the same:
assert(2 + 2 > 5);
// AssertionError: The expression evaluated to a falsy value:
//
//   assert(2 + 2 > 5)
javascript

assert.rejects(asyncFn[, error][, message])#

Awaits the asyncFn promise or, if asyncFn is a function, immediately calls the function and awaits the returned promise to complete. It will then check that the promise is rejected.

If asyncFn is a function and it throws an error synchronously, assert.rejects() will return a rejected Promise with that error. If the function does not return a promise, assert.rejects() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE error. In both cases the error handler is skipped.

Besides the async nature to await the completion behaves identically to assert.throws().

If specified, error can be a Class, <RegExp>, a validation function, an object where each property will be tested for, or an instance of error where each property will be tested for including the non-enumerable message and name properties.

If specified, message will be the message provided by the AssertionError if the asyncFn fails to reject.

import assert from 'node:assert/strict';

await assert.rejects(
  async () => {
    throw new TypeError('Wrong value');
  },
  {
    name: 'TypeError',
    message: 'Wrong value',
  },
);
const assert = require('node:assert/strict');

(async () => {
  await assert.rejects(
    async () => {
      throw new TypeError('Wrong value');
    },
    {
      name: 'TypeError',
      message: 'Wrong value',
    },
  );
})();
javascript
import assert from 'node:assert/strict';

await assert.rejects(
  async () => {
    throw new TypeError('Wrong value');
  },
  (err) => {
    assert.strictEqual(err.name, 'TypeError');
    assert.strictEqual(err.message, 'Wrong value');
    return true;
  },
);
const assert = require('node:assert/strict');

(async () => {
  await assert.rejects(
    async () => {
      throw new TypeError('Wrong value');
    },
    (err) => {
      assert.strictEqual(err.name, 'TypeError');
      assert.strictEqual(err.message, 'Wrong value');
      return true;
    },
  );
})();
javascript
import assert from 'node:assert/strict';

assert.rejects(
  Promise.reject(new Error('Wrong value')),
  Error,
).then(() => {
  // ...
});
const assert = require('node:assert/strict');

assert.rejects(
  Promise.reject(new Error('Wrong value')),
  Error,
).then(() => {
  // ...
});
javascript

error cannot be a string. If a string is provided as the second argument, then error is assumed to be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Please read the example in assert.throws() carefully if using a string as the second argument gets considered.

assert.strictEqual(actual, expected[, message])#

  • actual <any>
  • expected <any>
  • message <string> | <Error> | <Function> Postfix printf-like arguments in case it's used as format string. If message is a function, it is called in case of a comparison failure. The function receives the actual and expected arguments and has to return a string that is going to be used as error message. printf-like format strings and functions are beneficial for performance reasons in case arguments are passed through. In addition, it allows nice formatting with ease.

Tests strict equality between the actual and expected parameters as determined by Object.is().

import assert from 'node:assert/strict';

assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2

assert.strictEqual(1, 1);
// OK

assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
//          ^

const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(apples, oranges, 'apples %s !== oranges %s', apples, oranges);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical

assert.strictEqual(apples, oranges, (actual, expected) => {
  // Do 'heavy' computations
  return `I expected ${expected} but I got ${actual}`;
});
// AssertionError [ERR_ASSERTION]: I expected oranges but I got apples
const assert = require('node:assert/strict');

assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2

assert.strictEqual(1, 1);
// OK

assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
//          ^

const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(apples, oranges, 'apples %s !== oranges %s', apples, oranges);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2

assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical

assert.strictEqual(apples, oranges, (actual, expected) => {
  // Do 'heavy' computations
  return `I expected ${expected} but I got ${actual}`;
});
// AssertionError [ERR_ASSERTION]: I expected oranges but I got apples
javascript

If the values are not strictly equal, an AssertionError is thrown with a message property set equal to the value of the message parameter. If the message parameter is undefined, a default error message is assigned. If the message parameter is an instance of <Error> then it will be thrown instead of the AssertionError.

assert.throws(fn[, error][, message])#

Expects the function fn to throw an error.

If specified, error can be a Class, <RegExp>, a validation function, a validation object where each property will be tested for strict deep equality, or an instance of error where each property will be tested for strict deep equality including the non-enumerable message and name properties. When using an object, it is also possible to use a regular expression, when validating against a string property. See below for examples.

If specified, message will be appended to the message provided by the AssertionError if the fn call fails to throw or in case the error validation fails.

Custom validation object/error instance:

import assert from 'node:assert/strict';

const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
  nested: true,
  baz: 'text',
};
err.reg = /abc/i;

assert.throws(
  () => {
    throw err;
  },
  {
    name: 'TypeError',
    message: 'Wrong value',
    info: {
      nested: true,
      baz: 'text',
    },
    // Only properties on the validation object will be tested for.
    // Using nested objects requires all properties to be present. Otherwise
    // the validation is going to fail.
  },
);

// Using regular expressions to validate error properties:
assert.throws(
  () => {
    throw err;
  },
  {
    // The `name` and `message` properties are strings and using regular
    // expressions on those will match against the string. If they fail, an
    // error is thrown.
    name: /^TypeError$/,
    message: /Wrong/,
    foo: 'bar',
    info: {
      nested: true,
      // It is not possible to use regular expressions for nested properties!
      baz: 'text',
    },
    // The `reg` property contains a regular expression and only if the
    // validation object contains an identical regular expression, it is going
    // to pass.
    reg: /abc/i,
  },
);

// Fails due to the different `message` and `name` properties:
assert.throws(
  () => {
    const otherErr = new Error('Not found');
    // Copy all enumerable properties from `err` to `otherErr`.
    for (const [key, value] of Object.entries(err)) {
      otherErr[key] = value;
    }
    throw otherErr;
  },
  // The error's `message` and `name` properties will also be checked when using
  // an error as validation object.
  err,
);
const assert = require('node:assert/strict');

const err = new TypeError('Wrong value');
err.code = 404;
err.foo = 'bar';
err.info = {
  nested: true,
  baz: 'text',
};
err.reg = /abc/i;

assert.throws(
  () => {
    throw err;
  },
  {
    name: 'TypeError',
    message: 'Wrong value',
    info: {
      nested: true,
      baz: 'text',
    },
    // Only properties on the validation object will be tested for.
    // Using nested objects requires all properties to be present. Otherwise
    // the validation is going to fail.
  },
);

// Using regular expressions to validate error properties:
assert.throws(
  () => {
    throw err;
  },
  {
    // The `name` and `message` properties are strings and using regular
    // expressions on those will match against the string. If they fail, an
    // error is thrown.
    name: /^TypeError$/,
    message: /Wrong/,
    foo: 'bar',
    info: {
      nested: true,
      // It is not possible to use regular expressions for nested properties!
      baz: 'text',
    },
    // The `reg` property contains a regular expression and only if the
    // validation object contains an identical regular expression, it is going
    // to pass.
    reg: /abc/i,
  },
);

// Fails due to the different `message` and `name` properties:
assert.throws(
  () => {
    const otherErr = new Error('Not found');
    // Copy all enumerable properties from `err` to `otherErr`.
    for (const [key, value] of Object.entries(err)) {
      otherErr[key] = value;
    }
    throw otherErr;
  },
  // The error's `message` and `name` properties will also be checked when using
  // an error as validation object.
  err,
);
javascript

Validate instanceof using constructor:

import assert from 'node:assert/strict';

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  Error,
);
const assert = require('node:assert/strict');

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  Error,
);
javascript

Validate error message using <RegExp>:

Using a regular expression runs .toString on the error object, and will therefore also include the error name.

import assert from 'node:assert/strict';

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  /^Error: Wrong value$/,
);
const assert = require('node:assert/strict');

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  /^Error: Wrong value$/,
);
javascript

Custom error validation:

The function must return true to indicate all internal validations passed. It will otherwise fail with an AssertionError.

import assert from 'node:assert/strict';

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  (err) => {
    assert(err instanceof Error);
    assert(/value/.test(err));
    // Avoid returning anything from validation functions besides `true`.
    // Otherwise, it's not clear what part of the validation failed. Instead,
    // throw an error about the specific validation that failed (as done in this
    // example) and add as much helpful debugging information to that error as
    // possible.
    return true;
  },
  'unexpected error',
);
const assert = require('node:assert/strict');

assert.throws(
  () => {
    throw new Error('Wrong value');
  },
  (err) => {
    assert(err instanceof Error);
    assert(/value/.test(err));
    // Avoid returning anything from validation functions besides `true`.
    // Otherwise, it's not clear what part of the validation failed. Instead,
    // throw an error about the specific validation that failed (as done in this
    // example) and add as much helpful debugging information to that error as
    // possible.
    return true;
  },
  'unexpected error',
);
javascript

error cannot be a string. If a string is provided as the second argument, then error is assumed to be omitted and the string will be used for message instead. This can lead to easy-to-miss mistakes. Using the same message as the thrown error message is going to result in an ERR_AMBIGUOUS_ARGUMENT error. Please read the example below carefully if using a string as the second argument gets considered:

import assert from 'node:assert/strict';

function throwingFirst() {
  throw new Error('First');
}

function throwingSecond() {
  throw new Error('Second');
}

function notThrowing() {}

// The second argument is a string and the input function threw an Error.
// The first case will not throw as it does not match for the error message
// thrown by the input function!
assert.throws(throwingFirst, 'Second');
// In the next example the message has no benefit over the message from the
// error and since it is not clear if the user intended to actually match
// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// The string is only used (as message) in case the function does not throw:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second

// If it was intended to match for the error message do this instead:
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);

// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]
const assert = require('node:assert/strict');

function throwingFirst() {
  throw new Error('First');
}

function throwingSecond() {
  throw new Error('Second');
}

function notThrowing() {}

// The second argument is a string and the input function threw an Error.
// The first case will not throw as it does not match for the error message
// thrown by the input function!
assert.throws(throwingFirst, 'Second');
// In the next example the message has no benefit over the message from the
// error and since it is not clear if the user intended to actually match
// against the error message, Node.js throws an `ERR_AMBIGUOUS_ARGUMENT` error.
assert.throws(throwingSecond, 'Second');
// TypeError [ERR_AMBIGUOUS_ARGUMENT]

// The string is only used (as message) in case the function does not throw:
assert.throws(notThrowing, 'Second');
// AssertionError [ERR_ASSERTION]: Missing expected exception: Second

// If it was intended to match for the error message do this instead:
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);

// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// AssertionError [ERR_ASSERTION]
javascript

Due to the confusing error-prone notation, avoid a string as the second argument.

assert.partialDeepStrictEqual(actual, expected[, message])#

Tests for partial deep equality between the actual and expected parameters. "Deep" equality means that the enumerable "own" properties of child objects are recursively evaluated also by the following rules. "Partial" equality means that only properties that exist on the expected parameter are going to be compared.

This method always passes the same test cases as assert.deepStrictEqual(), behaving as a super set of it.

Comparison details#

  • Primitive values are compared using Object.is().
  • Type tags of objects should be the same.
  • [[Prototype]] of objects are not compared.
  • Only enumerable "own" properties are considered.
  • <Error> names, messages, causes, and errors are always compared, even if these are not enumerable properties. errors is also compared.
  • Enumerable own <Symbol> properties are compared as well.
  • Object wrappers are compared both as objects and unwrapped values.
  • Object properties are compared unordered.
  • <Map> keys and <Set> items are compared unordered.
  • Recursion stops when both sides differ or both sides encounter a circular reference.
  • <WeakMap>, <WeakSet> and <Promise> instances are not compared structurally. They are only equal if they reference the same object. Any comparison between different WeakMap, WeakSet, or Promise instances will result in inequality, even if they contain the same content.
  • <RegExp> lastIndex, flags, and source are always compared, even if these are not enumerable properties.
  • Holes in sparse arrays are ignored.
import assert from 'node:assert';

assert.partialDeepStrictEqual(
  { a: { b: { c: 1 } } },
  { a: { b: { c: 1 } } },
);
// OK

assert.partialDeepStrictEqual(
  { a: 1, b: 2, c: 3 },
  { b: 2 },
);
// OK

assert.partialDeepStrictEqual(
  [1, 2, 3, 4, 5, 6, 7, 8, 9],
  [4, 5, 8],
);
// OK

assert.partialDeepStrictEqual(
  new Set([{ a: 1 }, { b: 1 }]),
  new Set([{ a: 1 }]),
);
// OK

assert.partialDeepStrictEqual(
  new Map([['key1', 'value1'], ['key2', 'value2']]),
  new Map([['key2', 'value2']]),
);
// OK

assert.partialDeepStrictEqual(123n, 123n);
// OK

assert.partialDeepStrictEqual(
  [1, 2, 3, 4, 5, 6, 7, 8, 9],
  [5, 4, 8],
);
// AssertionError

assert.partialDeepStrictEqual(
  { a: 1 },
  { a: 1, b: 2 },
);
// AssertionError

assert.partialDeepStrictEqual(
  { a: { b: 2 } },
  { a: { b: '2' } },
);
// AssertionError
const assert = require('node:assert');

assert.partialDeepStrictEqual(
  { a: { b: { c: 1 } } },
  { a: { b: { c: 1 } } },
);
// OK

assert.partialDeepStrictEqual(
  { a: 1, b: 2, c: 3 },
  { b: 2 },
);
// OK

assert.partialDeepStrictEqual(
  [1, 2, 3, 4, 5, 6, 7, 8, 9],
  [4, 5, 8],
);
// OK

assert.partialDeepStrictEqual(
  new Set([{ a: 1 }, { b: 1 }]),
  new Set([{ a: 1 }]),
);
// OK

assert.partialDeepStrictEqual(
  new Map([['key1', 'value1'], ['key2', 'value2']]),
  new Map([['key2', 'value2']]),
);
// OK

assert.partialDeepStrictEqual(123n, 123n);
// OK

assert.partialDeepStrictEqual(
  [1, 2, 3, 4, 5, 6, 7, 8, 9],
  [5, 4, 8],
);
// AssertionError

assert.partialDeepStrictEqual(
  { a: 1 },
  { a: 1, b: 2 },
);
// AssertionError

assert.partialDeepStrictEqual(
  { a: { b: 2 } },
  { a: { b: '2' } },
);
// AssertionError
javascript

Async hooks#

Stability: 1 - Experimental. Please migrate away from this API, if you can. We do not recommend using the createHook, AsyncHook, and executionAsyncResource APIs as they have usability issues, safety risks, and performance implications. Async context tracking use cases are better served by the stable AsyncLocalStorage API. If you have a use case for createHook, AsyncHook, or executionAsyncResource beyond the context tracking need solved by AsyncLocalStorage or diagnostics data currently provided by Diagnostics Channel, please open an issue at https://github.com/nodejs/node/issues describing your use case so we can create a more purpose-focused API.

We strongly discourage the use of the async_hooks API. Other APIs that can cover most of its use cases include:

The node:async_hooks module provides an API to track asynchronous resources. It can be accessed using:

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

Terminology#

An asynchronous resource represents an object with an associated callback. This callback may be called multiple times, such as the 'connection' event in net.createServer(), or just a single time like in fs.open(). A resource can also be closed before the callback is called. AsyncHook does not explicitly distinguish between these different cases but will represent them as the abstract concept that is a resource.

If Workers are used, each thread has an independent async_hooks interface, and each thread will use a new set of async IDs.

Overview#

Following is a simple overview of the public API.

import async_hooks from 'node:async_hooks';

// Return the ID of the current execution context.
const eid = async_hooks.executionAsyncId();

// Return the ID of the handle responsible for triggering the callback of the
// current execution scope to call.
const tid = async_hooks.triggerAsyncId();

// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook =
    async_hooks.createHook({ init, before, after, destroy, promiseResolve });

// Allow callbacks of this AsyncHook instance to call. This is not an implicit
// action after running the constructor, and must be explicitly run to begin
// executing callbacks.
asyncHook.enable();

// Disable listening for new asynchronous events.
asyncHook.disable();

//
// The following are the callbacks that can be passed to createHook().
//

// init() is called during object construction. The resource may not have
// completed construction when this callback runs. Therefore, all fields of the
// resource referenced by "asyncId" may not have been populated.
function init(asyncId, type, triggerAsyncId, resource) { }

// before() is called just before the resource's callback is called. It can be
// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
// time for requests (such as FSReqCallback).
function before(asyncId) { }

// after() is called just after the resource's callback has finished.
function after(asyncId) { }

// destroy() is called when the resource is destroyed.
function destroy(asyncId) { }

// promiseResolve() is called only for promise resources, when the
// resolve() function passed to the Promise constructor is invoked
// (either directly or through other means of resolving a promise).
function promiseResolve(asyncId) { }
const async_hooks = require('node:async_hooks');

// Return the ID of the current execution context.
const eid = async_hooks.executionAsyncId();

// Return the ID of the handle responsible for triggering the callback of the
// current execution scope to call.
const tid = async_hooks.triggerAsyncId();

// Create a new AsyncHook instance. All of these callbacks are optional.
const asyncHook =
    async_hooks.createHook({ init, before, after, destroy, promiseResolve });

// Allow callbacks of this AsyncHook instance to call. This is not an implicit
// action after running the constructor, and must be explicitly run to begin
// executing callbacks.
asyncHook.enable();

// Disable listening for new asynchronous events.
asyncHook.disable();

//
// The following are the callbacks that can be passed to createHook().
//

// init() is called during object construction. The resource may not have
// completed construction when this callback runs. Therefore, all fields of the
// resource referenced by "asyncId" may not have been populated.
function init(asyncId, type, triggerAsyncId, resource) { }

// before() is called just before the resource's callback is called. It can be
// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
// time for requests (such as FSReqCallback).
function before(asyncId) { }

// after() is called just after the resource's callback has finished.
function after(asyncId) { }

// destroy() is called when the resource is destroyed.
function destroy(asyncId) { }

// promiseResolve() is called only for promise resources, when the
// resolve() function passed to the Promise constructor is invoked
// (either directly or through other means of resolving a promise).
function promiseResolve(asyncId) { }
javascript

async_hooks.createHook(options)#

Registers functions to be called for different lifetime events of each async operation.

The callbacks init()/before()/after()/destroy() are called for the respective asynchronous event during a resource's lifetime.

All callbacks are optional. For example, if only resource cleanup needs to be tracked, then only the destroy callback needs to be passed. The specifics of all functions that can be passed to callbacks is in the Hook Callbacks section.

import { createHook } from 'node:async_hooks';

const asyncHook = createHook({
  init(asyncId, type, triggerAsyncId, resource) { },
  destroy(asyncId) { },
});
const async_hooks = require('node:async_hooks');

const asyncHook = async_hooks.createHook({
  init(asyncId, type, triggerAsyncId, resource) { },
  destroy(asyncId) { },
});
javascript

The callbacks will be inherited via the prototype chain:

class MyAsyncCallbacks {
  init(asyncId, type, triggerAsyncId, resource) { }
  destroy(asyncId) {}
}

class MyAddedCallbacks extends MyAsyncCallbacks {
  before(asyncId) { }
  after(asyncId) { }
}

const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
js

Because promises are asynchronous resources whose lifecycle is tracked via the async hooks mechanism, the init(), before(), after(), and destroy() callbacks must not be async functions that return promises.

Error handling#

If any AsyncHook callbacks throw, the application will print the stack trace and exit. The exit path does follow that of an uncaught exception, but all 'uncaughtException' listeners are removed, thus forcing the process to exit. The 'exit' callbacks will still be called unless the application is run with --abort-on-uncaught-exception, in which case a stack trace will be printed and the application exits, leaving a core file.

The reason for this error handling behavior is that these callbacks are running at potentially volatile points in an object's lifetime, for example during class construction and destruction. Because of this, it is deemed necessary to bring down the process quickly in order to prevent an unintentional abort in the future. This is subject to change in the future if a comprehensive analysis is performed to ensure an exception can follow the normal control flow without unintentional side effects.

Printing in AsyncHook callbacks#

Because printing to the console is an asynchronous operation, console.log() will cause AsyncHook callbacks to be called. Using console.log() or similar asynchronous operations inside an AsyncHook callback function will cause an infinite recursion. An easy solution to this when debugging is to use a synchronous logging operation such as fs.writeFileSync(file, msg, flag). This will print to the file and will not invoke AsyncHook recursively because it is synchronous.

import { writeFileSync } from 'node:fs';
import { format } from 'node:util';

function debug(...args) {
  // Use a function like this one when debugging inside an AsyncHook callback
  writeFileSync('log.out', `${format(...args)}\n`, { flag: 'a' });
}
const fs = require('node:fs');
const util = require('node:util');

function debug(...args) {
  // Use a function like this one when debugging inside an AsyncHook callback
  fs.writeFileSync('log.out', `${util.format(...args)}\n`, { flag: 'a' });
}
javascript

If an asynchronous operation is needed for logging, it is possible to keep track of what caused the asynchronous operation using the information provided by AsyncHook itself. The logging should then be skipped when it was the logging itself that caused the AsyncHook callback to be called. By doing this, the otherwise infinite recursion is broken.

Class: AsyncHook#

The class AsyncHook exposes an interface for tracking lifetime events of asynchronous operations.

asyncHook.enable()#

Enable the callbacks for a given AsyncHook instance. If no callbacks are provided, enabling is a no-op.

The AsyncHook instance is disabled by default. If the AsyncHook instance should be enabled immediately after creation, the following pattern can be used.

import { createHook } from 'node:async_hooks';

const hook = createHook(callbacks).enable();
const async_hooks = require('node:async_hooks');

const hook = async_hooks.createHook(callbacks).enable();
javascript

asyncHook.disable()#

Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.

For API consistency disable() also returns the AsyncHook instance.

Hook callbacks#

Key events in the lifetime of asynchronous events have been categorized into four areas: instantiation, before/after the callback is called, and when the instance is destroyed.

init(asyncId, type, triggerAsyncId, resource)#
  • asyncId <number> A unique ID for the async resource.
  • type <string> The type of the async resource.
  • triggerAsyncId <number> The unique ID of the async resource in whose execution context this async resource was created.
  • resource <Object> Reference to the resource representing the async operation, needs to be released during destroy.

Called when a class is constructed that has the possibility to emit an asynchronous event. This does not mean the instance must call before/after before destroy is called, only that the possibility exists.

This behavior can be observed by doing something like opening a resource then closing it before the resource can be used. The following snippet demonstrates this.

import { createServer } from 'node:net';

createServer().listen(function() { this.close(); });
// OR
clearTimeout(setTimeout(() => {}, 10));
require('node:net').createServer().listen(function() { this.close(); });
// OR
clearTimeout(setTimeout(() => {}, 10));
javascript

Every new resource is assigned an ID that is unique within the scope of the current Node.js instance.

type#

The type is a string identifying the type of resource that caused init to be called. Generally, it will correspond to the name of the resource's constructor.

The type of resources created by Node.js itself can change in any Node.js release. Valid values include TLSWRAP, TCPWRAP, TCPSERVERWRAP, GETADDRINFOREQWRAP, FSREQCALLBACK, Microtask, and Timeout. Inspect the source code of the Node.js version used to get the full list.

Furthermore users of AsyncResource create async resources independent of Node.js itself.

There is also the PROMISE resource type, which is used to track Promise instances and asynchronous work scheduled by them. The Promises are only tracked when trackPromises option is set to true.

Users are able to define their own type when using the public embedder API.

It is possible to have type name collisions. Embedders are encouraged to use unique prefixes, such as the npm package name, to prevent collisions when listening to the hooks.

triggerAsyncId#

triggerAsyncId is the asyncId of the resource that caused (or "triggered") the new resource to initialize and that caused init to call. This is different from async_hooks.executionAsyncId() that only shows when a resource was created, while triggerAsyncId shows why a resource was created.

The following is a simple demonstration of triggerAsyncId:

import { createHook, executionAsyncId } from 'node:async_hooks';
import { stdout } from 'node:process';
import net from 'node:net';
import fs from 'node:fs';

createHook({
  init(asyncId, type, triggerAsyncId) {
    const eid = executionAsyncId();
    fs.writeSync(
      stdout.fd,
      `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
  },
}).enable();

net.createServer((conn) => {}).listen(8080);
const { createHook, executionAsyncId } = require('node:async_hooks');
const { stdout } = require('node:process');
const net = require('node:net');
const fs = require('node:fs');

createHook({
  init(asyncId, type, triggerAsyncId) {
    const eid = executionAsyncId();
    fs.writeSync(
      stdout.fd,
      `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
  },
}).enable();

net.createServer((conn) => {}).listen(8080);
javascript

Output when hitting the server with nc localhost 8080:

TCPSERVERWRAP(5): trigger: 1 execution: 1
TCPWRAP(7): trigger: 5 execution: 0
console

The TCPSERVERWRAP is the server which receives the connections.

The TCPWRAP is the new connection from the client. When a new connection is made, the TCPWrap instance is immediately constructed. This happens outside of any JavaScript stack. (An executionAsyncId() of 0 means that it is being executed from C++ with no JavaScript stack above it.) With only that information, it would be impossible to link resources together in terms of what caused them to be created, so triggerAsyncId is given the task of propagating what resource is responsible for the new resource's existence.

resource#

resource is an object that represents the actual async resource that has been initialized. The API to access the object may be specified by the creator of the resource. Resources created by Node.js itself are internal and may change at any time. Therefore no API is specified for these.

In some cases the resource object is reused for performance reasons, it is thus not safe to use it as a key in a WeakMap or add properties to it.

Asynchronous context example#

The context tracking use case is covered by the stable API AsyncLocalStorage. This example only illustrates async hooks operation but AsyncLocalStorage fits better to this use case.

The following is an example with additional information about the calls to init between the before and after calls, specifically what the callback to listen() will look like. The output formatting is slightly more elaborate to make calling context easier to see.

import async_hooks from 'node:async_hooks';
import fs from 'node:fs';
import net from 'node:net';
import { stdout } from 'node:process';
const { fd } = stdout;

let indent = 0;
async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    const eid = async_hooks.executionAsyncId();
    const indentStr = ' '.repeat(indent);
    fs.writeSync(
      fd,
      `${indentStr}${type}(${asyncId}):` +
      ` trigger: ${triggerAsyncId} execution: ${eid}\n`);
  },
  before(asyncId) {
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}before:  ${asyncId}\n`);
    indent += 2;
  },
  after(asyncId) {
    indent -= 2;
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}after:  ${asyncId}\n`);
  },
  destroy(asyncId) {
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}destroy:  ${asyncId}\n`);
  },
}).enable();

net.createServer(() => {}).listen(8080, () => {
  // Let's wait 10ms before logging the server started.
  setTimeout(() => {
    console.log('>>>', async_hooks.executionAsyncId());
  }, 10);
});
const async_hooks = require('node:async_hooks');
const fs = require('node:fs');
const net = require('node:net');
const { fd } = process.stdout;

let indent = 0;
async_hooks.createHook({
  init(asyncId, type, triggerAsyncId) {
    const eid = async_hooks.executionAsyncId();
    const indentStr = ' '.repeat(indent);
    fs.writeSync(
      fd,
      `${indentStr}${type}(${asyncId}):` +
      ` trigger: ${triggerAsyncId} execution: ${eid}\n`);
  },
  before(asyncId) {
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}before:  ${asyncId}\n`);
    indent += 2;
  },
  after(asyncId) {
    indent -= 2;
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}after:  ${asyncId}\n`);
  },
  destroy(asyncId) {
    const indentStr = ' '.repeat(indent);
    fs.writeSync(fd, `${indentStr}destroy:  ${asyncId}\n`);
  },
}).enable();

net.createServer(() => {}).listen(8080, () => {
  // Let's wait 10ms before logging the server started.
  setTimeout(() => {
    console.log('>>>', async_hooks.executionAsyncId());
  }, 10);
});
javascript

Output from only starting the server:

TCPSERVERWRAP(5): trigger: 1 execution: 1
TickObject(6): trigger: 5 execution: 1
before:  6
  Timeout(7): trigger: 6 execution: 6
after:   6
destroy: 6
before:  7
>>> 7
  TickObject(8): trigger: 7 execution: 7
after:   7
before:  8
after:   8
console

As illustrated in the example, executionAsyncId() and execution each specify the value of the current execution context; which is delineated by calls to before and after.

Only using execution to graph resource allocation results in the following:

  root(1)
     ^
     |
TickObject(6)
     ^
     |
 Timeout(7)
console

The TCPSERVERWRAP is not part of this graph, even though it was the reason for console.log() being called. This is because binding to a port without a host name is a synchronous operation, but to maintain a completely asynchronous API the user's callback is placed in a process.nextTick(). Which is why TickObject is present in the output and is a 'parent' for .listen() callback.

The graph only shows when a resource was created, not why, so to track the why use triggerAsyncId. Which can be represented with the following graph:

 bootstrap(1)
     |
     ˅
TCPSERVERWRAP(5)
     |
     ˅
 TickObject(6)
     |
     ˅
  Timeout(7)
console
before(asyncId)#

When an asynchronous operation is initiated (such as a TCP server receiving a new connection) or completes (such as writing data to disk) a callback is called to notify the user. The before callback is called just before said callback is executed. asyncId is the unique identifier assigned to the resource about to execute the callback.

The before callback will be called 0 to N times. The before callback will typically be called 0 times if the asynchronous operation was cancelled or, for example, if no connections are received by a TCP server. Persistent asynchronous resources like a TCP server will typically call the before callback multiple times, while other operations like fs.open() will call it only once.

after(asyncId)#

Called immediately after the callback specified in before is completed.

If an uncaught exception occurs during execution of the callback, then after will run after the 'uncaughtException' event is emitted or a domain's handler runs.

destroy(asyncId)#

Called after the resource corresponding to asyncId is destroyed. It is also called asynchronously from the embedder API emitDestroy().

Some resources depend on garbage collection for cleanup, so if a reference is made to the resource object passed to init it is possible that destroy will never be called, causing a memory leak in the application. If the resource does not depend on garbage collection, then this will not be an issue.

Using the destroy hook results in additional overhead because it enables tracking of Promise instances via the garbage collector.

promiseResolve(asyncId)#

Called when the resolve function passed to the Promise constructor is invoked (either directly or through other means of resolving a promise).

resolve() does not do any observable synchronous work.

The Promise is not necessarily fulfilled or rejected at this point if the Promise was resolved by assuming the state of another Promise.

new Promise((resolve) => resolve(true)).then((a) => {});
js

calls the following callbacks:

init for PROMISE with id 5, trigger id: 1
  promise resolve 5      # corresponds to resolve(true)
init for PROMISE with id 6, trigger id: 5  # the Promise returned by then()
  before 6               # the then() callback is entered
  promise resolve 6      # the then() callback resolves the promise by returning
  after 6
text

async_hooks.executionAsyncResource()#

  • Returns: <Object> The resource representing the current execution. Useful to store data within the resource.

Resource objects returned by executionAsyncResource() are most often internal Node.js handle objects with undocumented APIs. Using any functions or properties on the object is likely to crash your application and should be avoided.

Using executionAsyncResource() in the top-level execution context will return an empty object as there is no handle or request object to use, but having an object representing the top-level can be helpful.

import { open } from 'node:fs';
import { executionAsyncId, executionAsyncResource } from 'node:async_hooks';

console.log(executionAsyncId(), executionAsyncResource());  // 1 {}
open(new URL(import.meta.url), 'r', (err, fd) => {
  console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
});
const { open } = require('node:fs');
const { executionAsyncId, executionAsyncResource } = require('node:async_hooks');

console.log(executionAsyncId(), executionAsyncResource());  // 1 {}
open(__filename, 'r', (err, fd) => {
  console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
});
javascript

This can be used to implement continuation local storage without the use of a tracking Map to store the metadata:

import { createServer } from 'node:http';
import {
  executionAsyncId,
  executionAsyncResource,
  createHook,
} from 'node:async_hooks';
const sym = Symbol('state'); // Private symbol to avoid pollution

createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    const cr = executionAsyncResource();
    if (cr) {
      resource[sym] = cr[sym];
    }
  },
}).enable();

const server = createServer((req, res) => {
  executionAsyncResource()[sym] = { state: req.url };
  setTimeout(function() {
    res.end(JSON.stringify(executionAsyncResource()[sym]));
  }, 100);
}).listen(3000);
const { createServer } = require('node:http');
const {
  executionAsyncId,
  executionAsyncResource,
  createHook,
} = require('node:async_hooks');
const sym = Symbol('state'); // Private symbol to avoid pollution

createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    const cr = executionAsyncResource();
    if (cr) {
      resource[sym] = cr[sym];
    }
  },
}).enable();

const server = createServer((req, res) => {
  executionAsyncResource()[sym] = { state: req.url };
  setTimeout(function() {
    res.end(JSON.stringify(executionAsyncResource()[sym]));
  }, 100);
}).listen(3000);
javascript

async_hooks.executionAsyncId()#

  • Returns: <number> The asyncId of the current execution context. Useful to track when something calls.
import { executionAsyncId } from 'node:async_hooks';
import fs from 'node:fs';

console.log(executionAsyncId());  // 1 - bootstrap
const path = '.';
fs.open(path, 'r', (err, fd) => {
  console.log(executionAsyncId());  // 6 - open()
});
const async_hooks = require('node:async_hooks');
const fs = require('node:fs');

console.log(async_hooks.executionAsyncId());  // 1 - bootstrap
const path = '.';
fs.open(path, 'r', (err, fd) => {
  console.log(async_hooks.executionAsyncId());  // 6 - open()
});
javascript

The ID returned from executionAsyncId() is related to execution timing, not causality (which is covered by triggerAsyncId()):

const server = net.createServer((conn) => {
  // Returns the ID of the server, not of the new connection, because the
  // callback runs in the execution scope of the server's MakeCallback().
  async_hooks.executionAsyncId();

}).listen(port, () => {
  // Returns the ID of a TickObject (process.nextTick()) because all
  // callbacks passed to .listen() are wrapped in a nextTick().
  async_hooks.executionAsyncId();
});
js

Promise contexts may not get precise executionAsyncIds by default. See the section on promise execution tracking.

async_hooks.triggerAsyncId()#

  • Returns: <number> The ID of the resource responsible for calling the callback that is currently being executed.
const server = net.createServer((conn) => {
  // The resource that caused (or triggered) this callback to be called
  // was that of the new connection. Thus the return value of triggerAsyncId()
  // is the asyncId of "conn".
  async_hooks.triggerAsyncId();

}).listen(port, () => {
  // Even though all callbacks passed to .listen() are wrapped in a nextTick()
  // the callback itself exists because the call to the server's .listen()
  // was made. So the return value would be the ID of the server.
  async_hooks.triggerAsyncId();
});
js

Promise contexts may not get valid triggerAsyncIds by default. See the section on promise execution tracking.

async_hooks.asyncWrapProviders#

  • Returns: A map of provider types to the corresponding numeric id. This map contains all the event types that might be emitted by the async_hooks.init() event.

This feature suppresses the deprecated usage of process.binding('async_wrap').Providers. See: DEP0111

Promise execution tracking#

By default, promise executions are not assigned asyncIds due to the relatively expensive nature of the promise introspection API provided by V8. This means that programs using promises or async/await will not get correct execution and trigger ids for promise callback contexts by default.

import { executionAsyncId, triggerAsyncId } from 'node:async_hooks';

Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0
const { executionAsyncId, triggerAsyncId } = require('node:async_hooks');

Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0
javascript

Observe that the then() callback claims to have executed in the context of the outer scope even though there was an asynchronous hop involved. Also, the triggerAsyncId value is 0, which means that we are missing context about the resource that caused (triggered) the then() callback to be executed.

Installing async hooks via async_hooks.createHook enables promise execution tracking:

import { createHook, executionAsyncId, triggerAsyncId } from 'node:async_hooks';
createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6
const { createHook, executionAsyncId, triggerAsyncId } = require('node:async_hooks');

createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6
javascript

In this example, adding any actual hook function enabled the tracking of promises. There are two promises in the example above; the promise created by Promise.resolve() and the promise returned by the call to then(). In the example above, the first promise got the asyncId 6 and the latter got asyncId 7. During the execution of the then() callback, we are executing in the context of promise with asyncId 7. This promise was triggered by async resource 6.

Another subtlety with promises is that before and after callbacks are run only on chained promises. That means promises not created by then()/catch() will not have the before and after callbacks fired on them. For more details see the details of the V8 PromiseHooks API.

Disabling promise execution tracking#

Tracking promise execution can cause a significant performance overhead. To opt out of promise tracking, set trackPromises to false:

const { createHook } = require('node:async_hooks');
const { writeSync } = require('node:fs');
createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    // This init hook does not get called when trackPromises is set to false.
    writeSync(1, `init hook triggered for ${type}\n`);
  },
  trackPromises: false,  // Do not track promises.
}).enable();
Promise.resolve(1729);
import { createHook } from 'node:async_hooks';
import { writeSync } from 'node:fs';

createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    // This init hook does not get called when trackPromises is set to false.
    writeSync(1, `init hook triggered for ${type}\n`);
  },
  trackPromises: false,  // Do not track promises.
}).enable();
Promise.resolve(1729);
javascript

JavaScript embedder API#

Library developers that handle their own asynchronous resources performing tasks like I/O, connection pooling, or managing callback queues may use the AsyncResource JavaScript API so that all the appropriate callbacks are called.

Class: AsyncResource#

The documentation for this class has moved AsyncResource.

Class: AsyncLocalStorage#

The documentation for this class has moved AsyncLocalStorage.

Asynchronous context tracking#

Stability: 2 - Stable

Introduction#

These classes are used to associate state and propagate it throughout callbacks and promise chains. They allow storing data throughout the lifetime of a web request or any other asynchronous duration. It is similar to thread-local storage in other languages.

The AsyncLocalStorage and AsyncResource classes are part of the node:async_hooks module:

import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
const { AsyncLocalStorage, AsyncResource } = require('node:async_hooks');
javascript

Class: AsyncLocalStorage#

This class creates stores that stay coherent through asynchronous operations.

While you can create your own implementation on top of the node:async_hooks module, AsyncLocalStorage should be preferred as it is a performant and memory safe implementation that involves significant optimizations that are non-obvious to implement.

The following example uses AsyncLocalStorage to build a simple logger that assigns IDs to incoming HTTP requests and includes them in messages logged within each request.

import http from 'node:http';
import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage();

function logWithId(msg) {
  const id = asyncLocalStorage.getStore();
  console.log(`${id !== undefined ? id : '-'}:`, msg);
}

let idSeq = 0;
http.createServer((req, res) => {
  asyncLocalStorage.run(idSeq++, () => {
    logWithId('start');
    // Imagine any chain of async operations here
    setImmediate(() => {
      logWithId('finish');
      res.end();
    });
  });
}).listen(8080);

http.get('http://localhost:8080');
http.get('http://localhost:8080');
// Prints:
//   0: start
//   0: finish
//   1: start
//   1: finish
const http = require('node:http');
const { AsyncLocalStorage } = require('node:async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

function logWithId(msg) {
  const id = asyncLocalStorage.getStore();
  console.log(`${id !== undefined ? id : '-'}:`, msg);
}

let idSeq = 0;
http.createServer((req, res) => {
  asyncLocalStorage.run(idSeq++, () => {
    logWithId('start');
    // Imagine any chain of async operations here
    setImmediate(() => {
      logWithId('finish');
      res.end();
    });
  });
}).listen(8080);

http.get('http://localhost:8080');
http.get('http://localhost:8080');
// Prints:
//   0: start
//   0: finish
//   1: start
//   1: finish
javascript

Each instance of AsyncLocalStorage maintains an independent storage context. Multiple instances can safely exist simultaneously without risk of interfering with each other's data.

new AsyncLocalStorage([options])#

  • options <Object>
    • defaultValue <any> The default value to be used when no store is provided.
    • name <string> A name for the AsyncLocalStorage value.

Creates a new instance of AsyncLocalStorage. Store is only provided within a run() call or after an enterWith() call.

Static method: AsyncLocalStorage.bind(fn)#

  • fn <Function> The function to bind to the current execution context.
  • Returns: <Function> A new function that calls fn within the captured execution context.

Binds the given function to the current execution context.

Static method: AsyncLocalStorage.snapshot()#

  • Returns: <Function> A new function with the signature (fn: (...args) : R, ...args) : R.

Captures the current execution context and returns a function that accepts a function as an argument. Whenever the returned function is called, it calls the function passed to it within the captured context.

const asyncLocalStorage = new AsyncLocalStorage();
const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
console.log(result);  // returns 123
js

AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple async context tracking purposes, for example:

class Foo {
  #runInAsyncScope = AsyncLocalStorage.snapshot();

  get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
}

const foo = asyncLocalStorage.run(123, () => new Foo());
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
js

asyncLocalStorage.disable()#

Stability: 1 - Experimental

Disables the instance of AsyncLocalStorage. All subsequent calls to asyncLocalStorage.getStore() will return undefined until asyncLocalStorage.run() or asyncLocalStorage.enterWith() is called again.

When calling asyncLocalStorage.disable(), all current contexts linked to the instance will be exited.

Calling asyncLocalStorage.disable() is required before the asyncLocalStorage can be garbage collected. This does not apply to stores provided by the asyncLocalStorage, as those objects are garbage collected along with the corresponding async resources.

Use this method when the asyncLocalStorage is not in use anymore in the current process.

asyncLocalStorage.getStore()#

Returns the current store. If called outside of an asynchronous context initialized by calling asyncLocalStorage.run() or asyncLocalStorage.enterWith(), it returns undefined.

asyncLocalStorage.enterWith(store)#

Stability: 1 - Experimental

Transitions into the context for the remainder of the current synchronous execution and then persists the store through any following asynchronous calls.

Example:

const store = { id: 1 };
// Replaces previous store with the given store object
asyncLocalStorage.enterWith(store);
asyncLocalStorage.getStore(); // Returns the store object
someAsyncOperation(() => {
  asyncLocalStorage.getStore(); // Returns the same object
});
js

This transition will continue for the entire synchronous execution. This means that if, for example, the context is entered within an event handler subsequent event handlers will also run within that context unless specifically bound to another context with an AsyncResource. That is why run() should be preferred over enterWith() unless there are strong reasons to use the latter method.

const store = { id: 1 };

emitter.on('my-event', () => {
  asyncLocalStorage.enterWith(store);
});
emitter.on('my-event', () => {
  asyncLocalStorage.getStore(); // Returns the same object
});

asyncLocalStorage.getStore(); // Returns undefined
emitter.emit('my-event');
asyncLocalStorage.getStore(); // Returns the same object
js

asyncLocalStorage.name#

The name of the AsyncLocalStorage instance if provided.

asyncLocalStorage.run(store, callback[, ...args])#

Runs a function synchronously within a context and returns its return value. The store is not accessible outside of the callback function. The store is accessible to any asynchronous operations created within the callback.

The optional args are passed to the callback function.

If the callback function throws an error, the error is thrown by run() too. The stacktrace is not impacted by this call and the context is exited.

Example:

const store = { id: 2 };
try {
  asyncLocalStorage.run(store, () => {
    asyncLocalStorage.getStore(); // Returns the store object
    setTimeout(() => {
      asyncLocalStorage.getStore(); // Returns the store object
    }, 200);
    throw new Error();
  });
} catch (e) {
  asyncLocalStorage.getStore(); // Returns undefined
  // The error will be caught here
}
js

asyncLocalStorage.exit(callback[, ...args])#

Stability: 1 - Experimental

Runs a function synchronously outside of a context and returns its return value. The store is not accessible within the callback function or the asynchronous operations created within the callback. Any getStore() call done within the callback function will always return undefined.

The optional args are passed to the callback function.

If the callback function throws an error, the error is thrown by exit() too. The stacktrace is not impacted by this call and the context is re-entered.

Example:

// Within a call to run
try {
  asyncLocalStorage.getStore(); // Returns the store object or value
  asyncLocalStorage.exit(() => {
    asyncLocalStorage.getStore(); // Returns undefined
    throw new Error();
  });
} catch (e) {
  asyncLocalStorage.getStore(); // Returns the same object or value
  // The error will be caught here
}
js

asyncLocalStorage.withScope(store)#

Stability: 1 - Experimental

  • store <any>
  • Returns: {RunScope}

Creates a disposable scope that enters the given store and automatically restores the previous store value when the scope is disposed. This method is designed to work with JavaScript's explicit resource management (using syntax).

Example:

import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage();

{
  using _ = asyncLocalStorage.withScope('my-store');
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
}

console.log(asyncLocalStorage.getStore()); // Prints: undefined
const { AsyncLocalStorage } = require('node:async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

{
  using _ = asyncLocalStorage.withScope('my-store');
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
}

console.log(asyncLocalStorage.getStore()); // Prints: undefined
javascript

The withScope() method is particularly useful for managing context in synchronous code where you want to ensure the previous store value is restored when exiting a block, even if an error is thrown.

import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage();

try {
  using _ = asyncLocalStorage.withScope('my-store');
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
  throw new Error('test');
} catch (e) {
  // Store is automatically restored even after error
  console.log(asyncLocalStorage.getStore()); // Prints: undefined
}
const { AsyncLocalStorage } = require('node:async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();

try {
  using _ = asyncLocalStorage.withScope('my-store');
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
  throw new Error('test');
} catch (e) {
  // Store is automatically restored even after error
  console.log(asyncLocalStorage.getStore()); // Prints: undefined
}
javascript

Important: When using withScope() in async functions before the first await, be aware that the scope change will affect the caller's context. The synchronous portion of an async function (before the first await) runs immediately when called, and when it reaches the first await, it returns the promise to the caller. At that point, the scope change becomes visible in the caller's context and will persist in subsequent synchronous code until something else changes the scope value. For async operations, prefer using run() which properly isolates context across async boundaries.

import { AsyncLocalStorage } from 'node:async_hooks';

const asyncLocalStorage = new AsyncLocalStorage();

async function example() {
  using _ = asyncLocalStorage.withScope('my-store');
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
  await someAsyncOperation(); // Function pauses here and returns promise
  console.log(asyncLocalStorage.getStore()); // Prints: my-store
}

// Calling without await
example(); // Synchronous portion runs, then pauses at first await
// After the promise is returned, the scope 'my-store' is now active in caller!
console.log(asyncLocalStorage.getStore()); // Prints: my-store (unexpected!)
mjs

Usage with async/await#

If, within an async function, only one await call is to run within a context, the following pattern should be used:

async function fn() {
  await asyncLocalStorage.run(new Map(), () => {
    asyncLocalStorage.getStore().set('key', value);
    return foo(); // The return value of foo will be awaited
  });
}
js

In this example, the store is only available in the callback function and the functions called by foo. Outside of run, calling getStore will return undefined.

Troubleshooting: Context loss#

In most cases, AsyncLocalStorage works without issues. In rare situations, the current store is lost in one of the asynchronous operations.

If your code is callback-based, it is enough to promisify it with util.promisify() so it starts working with native promises.

If you need to use a callback-based API or your code assumes a custom thenable implementation, use the AsyncResource class to associate the asynchronous operation with the correct execution context. Find the function call responsible for the context loss by logging the content of asyncLocalStorage.getStore() after the calls you suspect are responsible for the loss. When the code logs undefined, the last callback called is probably responsible for the context loss.

Class: RunScope#

Stability: 1 - Experimental

A disposable scope returned by asyncLocalStorage.withScope() that automatically restores the previous store value when disposed. This class implements the Explicit Resource Management protocol and is designed to work with JavaScript's using syntax.

The scope automatically restores the previous store value when the using block exits, whether through normal completion or by throwing an error.

scope.dispose()#

Explicitly ends the scope and restores the previous store value. This method is idempotent: calling it multiple times has the same effect as calling it once.

The [Symbol.dispose]() method defers to dispose().

If withScope() is called without the using keyword, dispose() must be called manually to restore the previous store value. Forgetting to call dispose() will cause the store value to persist for the remainder of the current execution context:

import { AsyncLocalStorage } from 'node:async_hooks';

const storage = new AsyncLocalStorage();

// Without using, the scope must be disposed manually
const scope = storage.withScope('my-store');
// storage.getStore() === 'my-store' here

scope.dispose(); // Restore previous value
// storage.getStore() === undefined here
const { AsyncLocalStorage } = require('node:async_hooks');

const storage = new AsyncLocalStorage();

// Without using, the scope must be disposed manually
const scope = storage.withScope('my-store');
// storage.getStore() === 'my-store' here

scope.dispose(); // Restore previous value
// storage.getStore() === undefined here
javascript

Class: AsyncResource#

The class AsyncResource is designed to be extended by the embedder's async resources. Using this, users can easily trigger the lifetime events of their own resources.

The init hook will trigger when an AsyncResource is instantiated.

The following is an overview of the AsyncResource API.

import { AsyncResource, executionAsyncId } from 'node:async_hooks';

// AsyncResource() is meant to be extended. Instantiating a
// new AsyncResource() also triggers init. If triggerAsyncId is omitted then
// async_hook.executionAsyncId() is used.
const asyncResource = new AsyncResource(
  type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
);

// Run a function in the execution context of the resource. This will
// * establish the context of the resource
// * trigger the AsyncHooks before callbacks
// * call the provided function `fn` with the supplied arguments
// * trigger the AsyncHooks after callbacks
// * restore the original execution context
asyncResource.runInAsyncScope(fn, thisArg, ...args);

// Call AsyncHooks destroy callbacks.
asyncResource.emitDestroy();

// Return the unique ID assigned to the AsyncResource instance.
asyncResource.asyncId();

// Return the trigger ID for the AsyncResource instance.
asyncResource.triggerAsyncId();
const { AsyncResource, executionAsyncId } = require('node:async_hooks');

// AsyncResource() is meant to be extended. Instantiating a
// new AsyncResource() also triggers init. If triggerAsyncId is omitted then
// async_hook.executionAsyncId() is used.
const asyncResource = new AsyncResource(
  type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
);

// Run a function in the execution context of the resource. This will
// * establish the context of the resource
// * trigger the AsyncHooks before callbacks
// * call the provided function `fn` with the supplied arguments
// * trigger the AsyncHooks after callbacks
// * restore the original execution context
asyncResource.runInAsyncScope(fn, thisArg, ...args);

// Call AsyncHooks destroy callbacks.
asyncResource.emitDestroy();

// Return the unique ID assigned to the AsyncResource instance.
asyncResource.asyncId();

// Return the trigger ID for the AsyncResource instance.
asyncResource.triggerAsyncId();
javascript

new AsyncResource(type[, options])#

  • type <string> The type of async event.
  • options <Object>
    • 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.

Example usage:

class DBQuery extends AsyncResource {
  constructor(db) {
    super('DBQuery');
    this.db = db;
  }

  getInfo(query, callback) {
    this.db.get(query, (err, data) => {
      this.runInAsyncScope(callback, null, err, data);
    });
  }

  close() {
    this.db = null;
    this.emitDestroy();
  }
}
js

Static method: AsyncResource.bind(fn[, type[, thisArg]])#

  • fn <Function> The function to bind to the current execution context.
  • type <string> An optional name to associate with the underlying AsyncResource.
  • thisArg <any>

Binds the given function to the current execution context.

asyncResource.bind(fn[, thisArg])#

  • fn <Function> The function to bind to the current AsyncResource.
  • thisArg <any>

Binds the given function to execute to this AsyncResource's scope.

asyncResource.runInAsyncScope(fn[, thisArg, ...args])#

  • fn <Function> The function to call in the execution context of this async resource.
  • thisArg <any> The receiver to be used for the function call.
  • ...args <any> Optional arguments to pass to the function.

Call the provided function with the provided arguments in the execution context of the async resource. This will establish the context, trigger the AsyncHooks before callbacks, call the function, trigger the AsyncHooks after callbacks, and then restore the original execution context.

asyncResource.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.

asyncResource.asyncId()#

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

asyncResource.triggerAsyncId()#

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

Using AsyncResource for a Worker thread pool#

The following example shows how to use the AsyncResource class to properly provide async tracking for a Worker pool. Other resource pools, such as database connection pools, can follow a similar model.

Assuming that the task is adding two numbers, using a file named task_processor.js with the following content:

import { parentPort } from 'node:worker_threads';
parentPort.on('message', (task) => {
  parentPort.postMessage(task.a + task.b);
});
const { parentPort } = require('node:worker_threads');
parentPort.on('message', (task) => {
  parentPort.postMessage(task.a + task.b);
});
javascript

a Worker pool around it could use the following structure:

import { AsyncResource } from 'node:async_hooks';
import { EventEmitter } from 'node:events';
import { Worker } from 'node:worker_threads';

const kTaskInfo = Symbol('kTaskInfo');
const kWorkerFreedEvent = Symbol('kWorkerFreedEvent');

class WorkerPoolTaskInfo extends AsyncResource {
  constructor(callback) {
    super('WorkerPoolTaskInfo');
    this.callback = callback;
  }

  done(err, result) {
    this.runInAsyncScope(this.callback, null, err, result);
    this.emitDestroy();  // `TaskInfo`s are used only once.
  }
}

export default class WorkerPool extends EventEmitter {
  constructor(numThreads) {
    super();
    this.numThreads = numThreads;
    this.workers = [];
    this.freeWorkers = [];
    this.tasks = [];

    for (let i = 0; i < numThreads; i++)
      this.addNewWorker();

    // Any time the kWorkerFreedEvent is emitted, dispatch
    // the next task pending in the queue, if any.
    this.on(kWorkerFreedEvent, () => {
      if (this.tasks.length > 0) {
        const { task, callback } = this.tasks.shift();
        this.runTask(task, callback);
      }
    });
  }

  addNewWorker() {
    const worker = new Worker(new URL('task_processor.js', import.meta.url));
    worker.on('message', (result) => {
      // In case of success: Call the callback that was passed to `runTask`,
      // remove the `TaskInfo` associated with the Worker, and mark it as free
      // again.
      worker[kTaskInfo].done(null, result);
      worker[kTaskInfo] = null;
      this.freeWorkers.push(worker);
      this.emit(kWorkerFreedEvent);
    });
    worker.on('error', (err) => {
      // In case of an uncaught exception: Call the callback that was passed to
      // `runTask` with the error.
      if (worker[kTaskInfo])
        worker[kTaskInfo].done(err, null);
      else
        this.emit('error', err);
      // Remove the worker from the list and start a new Worker to replace the
      // current one.
      this.workers.splice(this.workers.indexOf(worker), 1);
      this.addNewWorker();
    });
    this.workers.push(worker);
    this.freeWorkers.push(worker);
    this.emit(kWorkerFreedEvent);
  }

  runTask(task, callback) {
    if (this.freeWorkers.length === 0) {
      // No free threads, wait until a worker thread becomes free.
      this.tasks.push({ task, callback });
      return;
    }

    const worker = this.freeWorkers.pop();
    worker[kTaskInfo] = new WorkerPoolTaskInfo(callback);
    worker.postMessage(task);
  }

  close() {
    for (const worker of this.workers) worker.terminate();
  }
}
const { AsyncResource } = require('node:async_hooks');
const { EventEmitter } = require('node:events');
const path = require('node:path');
const { Worker } = require('node:worker_threads');

const kTaskInfo = Symbol('kTaskInfo');
const kWorkerFreedEvent = Symbol('kWorkerFreedEvent');

class WorkerPoolTaskInfo extends AsyncResource {
  constructor(callback) {
    super('WorkerPoolTaskInfo');
    this.callback = callback;
  }

  done(err, result) {
    this.runInAsyncScope(this.callback, null, err, result);
    this.emitDestroy();  // `TaskInfo`s are used only once.
  }
}

class WorkerPool extends EventEmitter {
  constructor(numThreads) {
    super();
    this.numThreads = numThreads;
    this.workers = [];
    this.freeWorkers = [];
    this.tasks = [];

    for (let i = 0; i < numThreads; i++)
      this.addNewWorker();

    // Any time the kWorkerFreedEvent is emitted, dispatch
    // the next task pending in the queue, if any.
    this.on(kWorkerFreedEvent, () => {
      if (this.tasks.length > 0) {
        const { task, callback } = this.tasks.shift();
        this.runTask(task, callback);
      }
    });
  }

  addNewWorker() {
    const worker = new Worker(path.resolve(__dirname, 'task_processor.js'));
    worker.on('message', (result) => {
      // In case of success: Call the callback that was passed to `runTask`,
      // remove the `TaskInfo` associated with the Worker, and mark it as free
      // again.
      worker[kTaskInfo].done(null, result);
      worker[kTaskInfo] = null;
      this.freeWorkers.push(worker);
      this.emit(kWorkerFreedEvent);
    });
    worker.on('error', (err) => {
      // In case of an uncaught exception: Call the callback that was passed to
      // `runTask` with the error.
      if (worker[kTaskInfo])
        worker[kTaskInfo].done(err, null);
      else
        this.emit('error', err);
      // Remove the worker from the list and start a new Worker to replace the
      // current one.
      this.workers.splice(this.workers.indexOf(worker), 1);
      this.addNewWorker();
    });
    this.workers.push(worker);
    this.freeWorkers.push(worker);
    this.emit(kWorkerFreedEvent);
  }

  runTask(task, callback) {
    if (this.freeWorkers.length === 0) {
      // No free threads, wait until a worker thread becomes free.
      this.tasks.push({ task, callback });
      return;
    }

    const worker = this.freeWorkers.pop();
    worker[kTaskInfo] = new WorkerPoolTaskInfo(callback);
    worker.postMessage(task);
  }

  close() {
    for (const worker of this.workers) worker.terminate();
  }
}

module.exports = WorkerPool;
javascript

Without the explicit tracking added by the WorkerPoolTaskInfo objects, it would appear that the callbacks are associated with the individual Worker objects. However, the creation of the Workers is not associated with the creation of the tasks and does not provide information about when tasks were scheduled.

This pool could be used as follows:

import WorkerPool from './worker_pool.js';
import os from 'node:os';

const pool = new WorkerPool(os.availableParallelism());

let finished = 0;
for (let i = 0; i < 10; i++) {
  pool.runTask({ a: 42, b: 100 }, (err, result) => {
    console.log(i, err, result);
    if (++finished === 10)
      pool.close();
  });
}
const WorkerPool = require('./worker_pool.js');
const os = require('node:os');

const pool = new WorkerPool(os.availableParallelism());

let finished = 0;
for (let i = 0; i < 10; i++) {
  pool.runTask({ a: 42, b: 100 }, (err, result) => {
    console.log(i, err, result);
    if (++finished === 10)
      pool.close();
  });
}
javascript

Integrating AsyncResource with EventEmitter#

Event listeners triggered by an EventEmitter may be run in a different execution context than the one that was active when eventEmitter.on() was called.

The following example shows how to use the AsyncResource class to properly associate an event listener with the correct execution context. The same approach can be applied to a Stream or a similar event-driven class.

import { createServer } from 'node:http';
import { AsyncResource, executionAsyncId } from 'node:async_hooks';

const server = createServer((req, res) => {
  req.on('close', AsyncResource.bind(() => {
    // Execution context is bound to the current outer scope.
  }));
  req.on('close', () => {
    // Execution context is bound to the scope that caused 'close' to emit.
  });
  res.end();
}).listen(3000);
const { createServer } = require('node:http');
const { AsyncResource, executionAsyncId } = require('node:async_hooks');

const server = createServer((req, res) => {
  req.on('close', AsyncResource.bind(() => {
    // Execution context is bound to the current outer scope.
  }));
  req.on('close', () => {
    // Execution context is bound to the scope that caused 'close' to emit.
  });
  res.end();
}).listen(3000);
javascript

Buffer#

Stability: 2 - Stable

Buffer objects are used to represent a fixed-length sequence of bytes. Many Node.js APIs support Buffers.

The Buffer class is a subclass of JavaScript's <Uint8Array> class and extends it with methods that cover additional use cases. Node.js APIs accept plain <Uint8Array>s wherever Buffers are supported as well.

While the Buffer class is available within the global scope, it is still recommended to explicitly reference it via an import or require statement.

import { Buffer } from 'node:buffer';

// Creates a zero-filled Buffer of length 10.
const buf1 = Buffer.