1. Use undici package
Just use it its fastest in benchmarks https://github.com/nodejs/undici
It’s built from the ground up with performance in mind. Undici
leverages modern Node.js features and optimizes the handling of HTTP requests and responses, making it an excellent choice for high-performance applications.
Example:
import { request } from 'undici';
async function fetchData(url) {
const { statusCode, headers, body } = await request(url);
const data = await body.text();
console.log(data);
}
fetchData('https://example.com');
2. Utilize undici Pool for Connection Reuse
If your application makes multiple requests to the same host, using a connection pool can dramatically improve performance.
Example:
import { Pool } from 'undici';
const pool = new Pool('https://example.com');
async function fetchData(path) {
const { statusCode, headers, body } = await pool.request({
path: path,
method: 'GET'
});
const data = await body.text();
console.log(data);
}
fetchData('/api/data');
Only use pool if you don't care about order of requests. https://github.com/nodejs/undici/blob/main/docs/docs/api/Pool.md
If you care about order use https://github.com/nodejs/undici/blob/main/docs/docs/api/Client.md
3. Add DNS Caching with cacheable-lookup
DNS resolution can introduce latency, especially when making multiple requests to the same host. By caching DNS lookups, you can avoid repeated DNS resolutions and reduce the time taken for each request. The cacheable-lookup library integrates seamlessly with undici to cache DNS lookups, improving request performance.
Example:
import { Client } from 'undici';
import CacheableLookup from 'cacheable-lookup';
const cacheable = new CacheableLookup();
const client = new Client('https://example.com', {
// @ts-expect-error https://github.com/szmarczak/cacheable-lookup/issues/79
connect: {
lookup: cacheable.lookup,
},
});
async function makeRequest() {
try {
const { statusCode, headers, body } = await client.request({
path: '/api/data',
method: 'GET',
});
const data = await body.text();
console.log(`Status: ${statusCode}`);
console.log('Headers:', headers);
console.log('Body:', data);
} catch (error) {
console.error('Request failed:', error.message);
} finally {
client.close(); // Close the client when done to free up resources
}
}
makeRequest();
4. Avoid Consuming the Body If You Don’t Need It
If you’re making HTTP requests where the response body is not needed, avoid consuming it. With undici
, you can simply ignore the response body if it’s not required.
Parsing JSON can significantly decrease performance, especially in high-throughput applications where many requests are handled simultaneously. When you parse JSON, the raw response data must be processed, converted into a JavaScript object, and then stored in memory. This process can be computationally expensive and memory-intensive, particularly when dealing with large JSON payloads or a high volume of requests.
If your application doesn’t need to work with the response data as a JSON object—perhaps you’re only interested in the status code, headers, or simply confirming that the request was successful—it’s best to avoid parsing the JSON altogether. Instead, you can handle the response as raw text or even skip processing the body entirely.
Example:
import { request } from 'undici';
async function sendPing(url) {
const { statusCode } = await request(url);
if (statusCode === 200) {
console.log('Ping successful');
}
// No need to consume the body here
}
sendPing('https://example.com/ping');
5. Use agentkeepalive
If you can’t switch to undici, and you want to still use for example axios, add https://www.npmjs.com/package/agentkeepalive
Example:
import axios from 'axios';
import { HttpsAgent } from 'agentkeepalive';
const keepaliveAgent = new HttpsAgent({
maxSockets: 100,
maxFreeSockets: 10,
timeout: 60000, // active socket keepalive for 60 seconds
freeSocketTimeout: 30000, // free socket keepalive for 30 seconds
});
// Create an Axios instance with the keep-alive agent
const axiosInstance = axios.create({
httpsAgent: keepaliveAgent,
});
// Now you can use this instance to make HTTPS requests
axiosInstance.get('https://example.com')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
agentkeepalive will add keepalive support and also disable Nagle’s algorithm
socket.setNoDelay(true)